“GDAL 实现矢量合并”,这标题看着简单,实际是搞 GIS 数据处理绕不开的一个核心操作。尤其是当你手里攒了一堆分幅的 shapefile、一堆按行政区切的 GeoJSON,或者从不同渠道拿到的同类矢量数据,要合成一张完整的图发出去、做分析或者入库,这个需求就立刻跳出来了。网上关于 ogr2ogr 的教程不少,但很多都是把命令行一贴就没下文了,合并完了怎么办、遇到属性对不上怎么办、大数据量卡死怎么办,这些真正耗时间的问题反而没人细讲。
这篇文章我把自己用 GDAL 做矢量合并的完整思路和踩过的坑整理出来,从最基础的命令行工具到 Python 批处理,再到百万级要素的性能优化,一次性讲透。
1. 内容整体设计与思路拆解
1.1 为什么用 GDAL 而不是 FME 或 ArcGIS
很多人第一反应是用 FME 或者 ArcGIS 的 Merge 工具做合并,这没问题,但我的主力环境是 Linux 服务器,数据量动不动就是几十个 G,桌面软件根本扛不住。GDAL 是命令行工具,资源占用低,Python 绑定又非常成熟,放在服务器上做批处理、定时任务都特别顺手。
用 GDAL 做矢量合并,核心逻辑其实就一句话:把多个数据源的几何要素读取出来,统一投影和字段结构,写入一个新的数据源。这个过程中真正决定成败的,不是命令本身,而是你对数据源格式、字段规则、坐标系这几个细节的掌控程度。
我之前接手过一个项目,要合并某区域 400 多个分幅的国土调查数据,每个分幅都是一个独立 shapefile,总大小接近 15GB。如果用 ArcGIS,光打开图层列表就能卡半天,更别提合并了。后来用 GDAL 写了个批处理脚本,分区域并行跑,四十分钟左右全部合并完成。
1.2 合并流程的三种常见场景
矢量合并不是只有“把文件堆一起”这一种玩法,实际业务里通常分成三种场景:
场景一:同构数据合并。多个 shapefile 字段名、字段类型、坐标系完全一致,比如都是从同一个软件导出的分幅数据,这种是最简单的,直接用 ogr2ogr 追加写入就行。
场景二:异构数据合并。不同来源的数据,字段名称不一样但含义相同,比如 A 文件的“NAME”字段和 B 文件的“XZQMC”字段实际都是村名。这种需要先做字段映射,统一结构后再合并。
场景三:数据入库整合。合并的最终目的是写入 PostGIS 或者 GeoPackage,这时候不仅要合并,还要考虑数据类型转换、空间索引创建、属性约束等一系列问题。
搞清楚自己属于哪种场景,再选对应的方案,比一上来就抄命令高效得多。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心细节解析与实操要点
2.1 认识 ogr2ogr 和 ogrmerge.py 的区别
GDAL 工具集里能完成矢量合并的有两个主力:一个是老牌的 ogr2ogr,一个是专门做合并的 ogrmerge.py。很多人不知道这两个工具到底怎么选,我直接说结论:
ogr2ogr 灵活度极高,适合做异构数据合并、字段映射、格式转换和坐标变换,但它的合并逻辑是“追加写入”,也就是你先确定一个目标文件,然后把其他文件的数据依次追加进去。
ogrmerge.py 是 GDAL 2.2 之后提供的专门脚本,适合同构数据的快速合并,尤其是目录下一堆分层文件要合成一个图层的时候,一行命令就能搞定,还能自动处理图层命名。
举两个典型的操作示例。先用 ogr2ogr 合并两个 shapefile:
bash复制ogr2ogr -f "ESRI Shapefile" merged.shp input1.shp
ogr2ogr -f "ESRI Shapefile" merged.shp input2.shp -append -nln merged
第一行创建新文件,第二行用 -append 追加第二个文件的数据。这里有一个关键点:-nln merged 必须写,它指定追加到哪个图层。如果不写,ogr2ogr 默认按照文件名生成图层名,追加的时候就会新建一个图层而不是追加到已有图层。
再用 ogrmerge.py 合并整个目录下的 GeoJSON:
bash复制ogrmerge.py -f GeoJSON -o merged.geojson /data/shp/*.geojson
这个命令会自动扫描目录下所有 GeoJSON 文件,合并成一个图层写入 merged.geojson。如果文件内部已经分了多个图层,ogrmerge.py 默认会按源图层名分别合并,想要强制合并成一个图层需要加 -single 参数:
bash复制ogrmerge.py -f GeoJSON -o merged.geojson /data/gdb/ -single
2.2 理解字段统一这个隐形门槛
矢量合并最容易翻车的不是几何,而是字段。GDAL 在追加数据时,如果源文件字段和目标文件字段不匹配,默认是不会自动映射的,结果就是字段值丢失、变成空值,或者直接报错。
先看个我在实际项目中遇到的报错:
code复制ERROR 1: Layer input2 already exists in output datasource "merged.shp".
这个错误出现在重复追加同一个图层的时候,原因是第二次执行 ogr2ogr 时目标文件里已经有了 input2 这个图层。解决办法就是我上面提到的,追加时指定 -nln merged 统一图层名。当然,如果你真要把 input2 里的字段做映射,命令就要换成这样:
bash复制ogr2ogr -f "ESRI Shapefile" merged.shp input2.shp -append -nln merged \
-sql "SELECT name, ST_GeomFromWKT(wkt) FROM input2" \
-dialect sqlite
这个命令里用了 SQLite 方言的 SQL 查询,ST_GeomFromWKT 表示把 input2 里的 wkt 字段解析成几何对象,然后只取 name 字段。这样追加的数据就自动统一到了目标文件的字段结构上。
2.3 投影坐标系和时间消耗的大坑
合并不同坐标系的数据,属于资深玩家也会踩的坑。如果你合并的 A 文件是 CGCS2000 的投影坐标,B 文件是 WGS84 经纬度,直接合并出来的数据在 GIS 里会错位得离谱,而且从属性表里根本看不出问题。
正确做法是合并前统一坐标系,用 ogr2ogr 的 -t_srs 参数强制转换:
bash复制ogr2ogr -f "ESRI Shapefile" merged_b.shp input_b.shp -t_srs "EPSG:4547"
更多时候你根本不知道源文件是什么坐标系,这时候要先读取元数据。用 ogrinfo 看一下:
bash复制ogrinfo -so input.shp input
输出里会明确列出 EXTENT 和 SRS,看
