You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js API导入Shapefile至PostGIS:仅点数据可用,线面报错

问题:Shapefile导入PostGIS时线/面类型触发RangeError错误

我用Node.js编写了/upload API接口,用于将Shapefile数据导入PostGIS数据库。流程是通过shapefile库读取Shapefile,先判断目标表是否存在,不存在则创建包含geom字段的表,再调用ogr2ogr命令完成数据导入。但目前仅能成功导入点类型Shapefile,导入线或面类型时会触发RangeError错误,报错源自shapefile库的Dbf模块,试过多个Shapefile都无法解决,希望得到解决方法。

核心代码

app.get('/upload', async (req, res) => {
    try {
        const basePath = req.headers.path;
        const fileName = basePath.match(/[^\\/]+$/);

        const shpData = await shapefile.read(basePath);
        const columnNames = Object.keys(shpData.features[0].properties);
        const tableName = fileName[0].split('.')[0];

        const tableExistsQuery = `SELECT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = '${tableName}')`;
        const { rows } = await client.query(tableExistsQuery);
        const tableExists = rows[0].exists;

        if (!tableExists) {
            const createTableQuery = `
                CREATE TABLE ${tableName} (
                    gid SERIAL PRIMARY KEY,
                    geom GEOMETRY,
                    ${columnNames.map(columnName => `${columnName} VARCHAR(255)`).join(', ')}
                )
            `;
            await client.query(createTableQuery);

            const uploadDataQuery = `ogr2ogr -f "PostgreSQL" PG:"dbname=${process.env.DATABASE} user=${process.env.USER} password=${process.env.PASSWORD} host=${process.env.HOST} port=${process.env.PORT}" ${basePath}.shp -nln ${tableName} -nlt PROMOTE_TO_MULTI`;
            exec(uploadDataQuery, (error, stdout, stderr) => {
                if (error) {
                    console.error(`Error: ${error.message}`);
                    return;
                }
                if (stderr) {
                    console.error(`stderr: ${stderr}`);
                    return;
                }
                console.log(`stdout: ${stdout}`);
            });
        }
        res.status(200).json({ message: 'Data uploaded in PostGIS database.' });

    } catch (error) {
        console.error('Error uploading data:', error);
        res.status(500).json({ error: 'Error uploading data.' });
    }
});

报错信息

2024-03-12 10:10:19 Error uploading data: RangeError: Offset is outside the bounds of the DataView
2024-03-12 10:10:19     at DataView.getUint8 ()
2024-03-12 10:10:19     at new Dbf (/usr/src/app/node_modules/shapefile/dist/shapefile.node.js:80:20)
2024-03-12 10:10:19     at /usr/src/app/node_modules/shapefile/dist/shapefile.node.js:65:14
2024-03-12 10:10:19     at process.processTicksAndRejections (node:internal/process/task_queues:95:5)

解决方法

1. 移除shapefile库依赖(最优方案)

既然最终用ogr2ogr完成数据导入,完全不需要先用shapefile库读取数据。直接通过文件名提取表名,让ogr2ogr自动处理表创建和字段映射:

  • 去掉shapefile.read相关代码,直接从basePath提取表名
  • 删除手动建表逻辑,ogr2ogr会根据Shapefile的字段自动创建对应表结构,包括正确的几何字段类型
  • 调整ogr2ogr命令,确保参数正确,同时处理异步执行问题(用util.promisify包装exec,等待导入完成再返回响应)

修改后的示例代码:

const { exec } = require('child_process');
const util = require('util');
const execPromise = util.promisify(exec);

app.get('/upload', async (req, res) => {
    try {
        const basePath = req.headers.path;
        const fileName = basePath.match(/[^\\/]+$/);
        const tableName = fileName[0].split('.')[0];

        const tableExistsQuery = `SELECT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = '${tableName}')`;
        const { rows } = await client.query(tableExistsQuery);
        const tableExists = rows[0].exists;

        if (!tableExists) {
            const uploadDataQuery = `ogr2ogr -f "PostgreSQL" PG:"dbname=${process.env.DATABASE} user=${process.env.USER} password=${process.env.PASSWORD} host=${process.env.HOST} port=${process.env.PORT}" ${basePath}.shp -nln ${tableName} -nlt PROMOTE_TO_MULTI -lco GEOMETRY_NAME=geom -lco FID=gid`;
            await execPromise(uploadDataQuery);
            console.log('Data imported successfully');
        }
        res.status(200).json({ message: 'Data uploaded in PostGIS database.' });

    } catch (error) {
        console.error('Error uploading data:', error);
        res.status(500).json({ error: 'Error uploading data.' });
    }
});

2. 若需手动建表,改用ogrinfo获取字段信息

如果必须手动创建表结构,不要用shapefile库,改用ogrinfo命令解析Shapefile的元数据:

  • 执行ogrinfo -so ${basePath}.shp ${tableName}获取字段名和类型
  • 解析命令输出,生成对应的建表SQL语句
  • 这样可以避免shapefile库的解析bug,同时获取更准确的字段类型(比如数值型、日期型,而不是统一用VARCHAR(255))

3. 升级或替换shapefile库

如果一定要保留shapefile库的使用:

  • 升级到该库的最新版本,查看是否有修复Dbf模块的相关bug
  • 替换为更稳定的Shapefile解析库,比如shpjs或@turf/turf中的相关模块

内容的提问来源于stack exchange,提问作者Daniel Riaño

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 03:56:15