☰
江苏省矢量地理数据从解压到入库:坐标系统一与裁剪合并全指南
2026/10/13 3:35:16 网站建设 项目流程

简介:江苏省矢量地理数据是一份基于OpenStreetMap开源数据、于2020年5月下载整理的省级GIS矢量数据集,覆盖江苏全省,适合GIS学习者、城乡规划与交通分析人员作为底图或分类数据源,可用于要素分类、空间查询、制图表达和基础空间分析。压缩包共92个文件,大小约54.6MB,核心为18个类别的shp矢量文件,每类配套dbf属性表、shx索引、prj坐标定义和xml元数据,目录结构清晰,可在ArcGIS、QGIS等软件中直接加载。数据内容涵盖交通路网、水系水域、建筑物、自然景点、兴趣点、土地利用等18类点、线、面要素,几何类型丰富;坐标系统一为WGS84,方便与GPS、在线地图及遥感影像叠加整合。目前已有1792人学习下载,可按类别单独调用,也可组合完成叠加分析、专题制图与区域概况展示,适合江苏省域教学实验和项目前期底图准备。

1. 江苏省矢量地理数据:压缩包里装的是什么,打开之后为什么总翻车

拿到一份“江苏省矢量地理数据.rar”,很多人第一反应是解压、拖进GIS、直接出图。然后就成了大型翻车现场:图层几百个、文件名全是字母数字组合、属性表中文乱码、坐标和底图错位几公里,甚至同一个县界的边界和相邻县接不上。这份压缩包本质上不是“一份数据”,而是把多个来源、多个坐标系、多个比例尺的shp、gdb、dwg素材打包在一起。它能直接解决“做江苏范围分析时没有统一底图”的痛点,但前提是你得先搞清楚它是谁、从哪来、坐标系是什么。本文要说的就是把这堆素材变成一套可靠、可复用、坐标统一的江苏省矢量底图的完整路径——从数据体检、坐标系统一到按区县裁剪合并,再到几类高频踩坑的排查手段,适合做规划分析、地图制图和WebGIS开发的从业者,新手照着能走通,熟手可以跳过基础直接看避坑章节。

2. 解压之后先别急着拖图:数据体检决定后面能不能用

2.1 压缩包不是文件夹结构:先列目录再动手

拿到“.rar”别直接用压缩软件“全部解压”,我习惯先列出rar内部的文件清单,确认里面是单层目录还是散装shp。如果直接解压,几百个文件铺一地,后面想找某个图层的工作量大到不想说话。

# Linux/macOS 下用 unrar 列出内容,不实际解压 unrar lb 江苏省矢量地理数据.rar | head -50 # lb 参数只列出文件名;head -50 只看前 50 条,先确认顶层目录结构

Windows 上没有现成的unrar,可以用 7-Zip 的7z l命令,效果一样。这一步核心是确认压缩包内是否带文件夹层级。常见做法是根据文件名前缀判断,比如DLTB开头是地类图斑、XZQ开头是行政区、DL开头是道路水系。如果文件名没有规律,就在解压之后用脚本做一次全量文件清单,再按扩展名分组。

2.2 shp 不是一个文件,是“一捆文件”:缺了哪个都会出问题

矢量数据最常见的是 shapefile,它不是单个文件,而是至少三件套:.shp存几何、.dbf存属性、.shx存索引。外加.prj存坐标系、.cpg存编码声明、.lyr存符号样式。“江苏省矢量地理数据”这种包最常见的坑是网上流传的压缩包缺.prj文件,或者是.prj文件写了但写错。

解压后先跑一遍完整性检查脚本,缺文件的直接列出来。

import os, glob # 检查目录下所有 shp 的配套文件是否齐全 shp_list = glob.glob("./data/**/*.shp", recursive=True) for shp in shp_list: base = shp[:-4] need = [".shp", ".shx", ".dbf", ".prj"] missing = [ext for ext in need if not os.path.exists(base + ext)] if missing: print(f"[缺文件] {base} 缺少 {missing}") else: print(f"[完整] {base}")

这段脚本会递归扫描所有子目录,把缺.prj或缺.shx的图层单独拎出来。**.shx缺失时 ArcGIS 或 QGIS 会自动重建,但部分第三方库会直接报错读不了**。.prj缺失是最致命的——后续所有坐标转换都无从谈起,后面第三章会专门讲。

2.3 属性表中文乱码:不是数据坏了,是编码没声明

江苏本地数据很多年代久远,属性表里的字段名和值用 GBK 编码存储,但.cpg文件可能不存在或者写的是UTF-8。这导致打开属性表之后,“名称”“代码”全变成“����”这类乱码。

# 用 file 命令看 dbf 的编码声明和实际编码 file -i 地类图斑.dbf # 输出示例: application/octet-stream; charset=unknown-8bit 说明没有有效编码信息

如果 dbf 文件没有编码声明,优先尝试用 QGIS 打开并指定GBK或GB2312加载。ArcGIS 中可以在图层属性里设置编码,但改了不生效是常有的事,根源在于 shapefile 的编码其实是写死在.cpg里的,ArcGIS 的界面设置对已有图层不生效。最可靠的做法是直接用 QGIS 的“数据源管理器”以指定编码重新加载一遍,确认不乱码之后再导出成带.cpg的 UTF-8 图层。这一步不值得省——等工作做到后期才发现字段值全是乱码,返工量是全局性的。

3. 坐标系统的坑:为什么两个图层在江苏范围内会错开几百米

3.1 江苏常见坐标系不止一种:2000、84、02 坐标一个都不能想当然

江苏的矢量数据来源复杂:国土部门的原始数据大多是 CGCS2000 高斯投影(代号CGCS2000_3_Degree_GK_Zone_38或..._Zone_39,中央经线分别为 120°E 和 123°E);测绘院移交的数据可能是 1980 西安坐标系;还有一批老数据是 1954 北京坐标系。更麻烦的是互联网底图(如在线天地图)用的是 Web Mercator,把 CGCS2000 的矢量直接拖到 Web 底图上,大概会偏出五六公里甚至更远,这种偏差肉眼一眼就能看出来。

判断图层的坐标系,第一优先看.prj文件里的文字描述。

# 直接查看 prj 文件内容 cat 某行政区划.prj # 出现 "CGCS2000" + "Gauss_Kruger" + "Zone_39" 就是 2000 国家大地坐标 3 度带 39 带

如果打开.prj发现是纯文本乱码,或者缺失.prj,就得用数据本身的佐证来判断。常见做法是用 QGIS 打开后和已知坐标系的参考图层比对,查看属性表里字段X、Y坐标的量级——如果 X 坐标是 8 位、Y 坐标是 7 位,基本可以判断是高斯投影加带号;如果 X 是 7 位没有带号,则是去带号的高斯坐标。这个地方是数据工作者最容易犯“想当然”错误的地方:压缩包是从一个桥梁工程群里流传出来的,里面所有图层全是按“国家 2000”标注,结果某几个乡镇的图斑是西安 80 坐标系,不做逐层检查就急着合并,后面全盘皆输。

3.2 用 QGIS 批量统一坐标系:少写代码也能全量搞定

拿到一份分不清坐标系的数据时,我一般会先抽 3 个图层目视定位,确认大概区域在江苏,再用批量工具给整个目录做统一投影。QGIS 的gdal工具集可以直接开箱用,不用写代码。

在 QGIS 菜单栏选择“处理” -> “工具箱”,搜索“重投影图层”,选择图层、目标坐标系EPSG:4526(即 CGCS2000 / 3-degree Gauss-Kruger zone 39,江苏中东部常用),另存为新文件。但逐层手点几十个图层效率太低,更实用的方案是直接用 GDAL 命令行脚本一次性批量处理:

# 批量转坐标系:所有 shp 统一转成 CGCS2000 高斯投影 zone 39(EPSG:4526) for shp in $(find /data/jspkg -name "*.shp"); do ogr2ogr -t_srs EPSG:4526 -overwrite \ "/data/unified/${shp##*/}" "$shp" \ -lco ENCODING=UTF-8 done

-t_srs指定转换后的坐标系;-overwrite防止同名文件冲突时中断;-lco ENCODING=UTF-8在输出文件里明确写入 UTF-8 编码声明,这一步顺手解决上一章说的乱码隐患。建议先小批量跑 3 个文件验证效果,再全量执行。注意ogr2ogr的输入输出文件不能放在同一个目录且同名,否则会在写文件时跳过原文件导致转换失败。

3.3 边界对不齐不是精度问题:投影带和中央经线才是元凶

在江苏范围做拼接裁剪时,最常遇到的现象是:乡镇边界和县界叠在一起,整体偏移 300 到 500 米,且偏移方向随位置变化,不是整体平移。很多人第一反应是数据精度差,然后去调容差、做捕捉,费了半天劲还是对不齐。其实真正原因大概率是两个图层的中央经线不一致——一个用了 120°E 的 38 带,另一个用了 123°E 的 39 带。虽然都属于 CGCS2000 高斯投影,但分带不同,离中央经线越远变形越大,表现就是局部偏移由西向东逐渐加大。

处理方法是先把统一到同一个中央经线的投影坐标系,然后再做几何操作。对江苏全境来说,跨 38 带和 39 带是常态,稳妥做法是选择区域中心附近的带号做统一基准,或者用EPSG:4545(CGCS2000 / 3-degree Gauss-Kruger CM 120E)处理偏西部分,用EPSG:4546(CM 123E)处理偏东部分,最后按比例把两部分合并。更省事的方式是直接转换为EPSG:4490(CGCS2000 地理坐标系,经纬度),所有叠加分析和切片显示用地理坐标,出图投影在最后一步再转。我自己的习惯是:分析过程全用地理坐标,只有制图输出才转投影坐标,能少掉一半以上的坐标系纠纷。

4. 按区县裁剪和图层合并:从散装数据到可用底图的完整操作

4.1 用行政区边界裁剪地类图斑:一步到位但要注意几何拓扑

拿到江苏省全境的地类图斑数据,实际项目中往往只需要某几个区县的范围。直接加载全量图层再裁剪,会导致渲染卡顿和后续统计量巨大。常见做法是用区县界去裁剪大图层,生成局部数据。

# 用 QGIS 内置的裁剪算法,通过命令行批量处理 qgis_process run native:clip \ --INPUT=/data/unified/江苏省地类图斑.shp \ --OVERLAY=/data/unified/某区县行政边界.shp \ --OUTPUT=/data/result/某区县地类图斑.shp

native:clip是 QGIS 矢量裁剪的标准算法;INPUT是被裁剪的大图层,OVERLAY是裁剪范围。裁剪结果会保留被裁剪图层的全部属性字段,不会带边界图层的字段。如果需要保留边界属性(比如区县名称、行政区代码),必须先做一次空间连接而不是直接裁剪。

这里有个坑:如果边界图层本身存在狭长多边形或相交缝隙,裁剪结果会在边界处出现细碎的“飞地碎屑”,即面积极小、形状怪异的面要素。QGIS 的裁剪算法不会自动清理这类碎屑。解决方法是裁剪后用native:filter按面积字段过滤一次,删除掉面积小于某个阈值的要素:

# 过滤掉面积小于 100 平方米的碎屑 qgis_process run native:filter \ --INPUT=/data/result/某区县地类图斑.shp \ --EXPRESSION='area($geometry) > 100' \ --OUTPUT=/data/result/某区县地类图斑_clean.shp

面积阈值按数据比例尺定,1:1 万的数据 100 平方米以下基本都是碎屑。如果只做制图可以留到出图前统一过滤,但如果要做面积汇总统计,必须在裁剪后立刻过滤,否则统计数值会带上大量无效面积。

4.2 按字段值批量拆分图层:一条 Python 调用代替手工点选

江苏全域数据里经常有“按地类代码把全省图斑拆成几十个分类图层”的需求,逐层“按属性选择 -> 导出”是手工作坊效率的做法。用 geopandas 可以一行循环搞定:

import geopandas as gpd # 读取全省数据 df = gpd.read_file("/data/unified/江苏省地类图斑.shp") # 按字段 dltbm(地类编码)拆分图层,每类单独输出一个 shp for code, group in df.groupby("dltbm"): out_path = f"/data/split/dltbm_{code}.shp" group.to_file(out_path, encoding="utf-8") print(f"{code}: {len(group)} 个要素 -> {out_path}")

groupby("dltbm")会按地类编码自动分组,每个分组就是一类地物的全部图斑。写入时指定encoding="utf-8"保证中文属性不乱码。这段脚本看起来简单,在实践里有几个细节值得说:to_file写出的 shapefile 字段名默认截断为 10 个字符,如果字段名过长会在大字段名后缀加下划线和数字,造成下游字段名无法对上。应对办法是在导出前用rename把长字段名缩短,或者直接输出 GeoJSON 或 GeoPackage 格式避免字段名限制:

group.to_file(f"/data/split/dltbm_{code}.gpkg", layer="features", driver="GPKG")

GeoPackage 对字段名长度没有 shapefile 那么苛刻,推荐作为内部成果格式。

4.3 合并多个图层:用 Gpkg 拼接比 shp 合并更稳定

把若干区县的数据合并成全省一份时,不建议直接用 ArcGIS 的 Merge 工具逐层添加,效率低且容易因字段结构不一致导致属性错位。用ogr2ogr的追加模式可以一次性归并:

# 第一个文件直接写入,其余文件追加到同一个目标图层 ogr2ogr -f GPKG /data/merged/江苏省全省.gpkg /data/part/某市.shp ogr2ogr -f GPKG -update -append \ /data/merged/江苏省全省.gpkg /data/part/另一市.shp \ -nln 江苏省全省

第一次执行创建目标文件,第二次及以后用-update -append追加写入;-nln指定目标图层名。这个方式的优势在于:不同来源的 shapefile 字段名可能略有差异,ogr2ogr默认可选-mapFieldType做字段类型映射,比手工改字段省事。但要注意追加前最好先统一各文件的坐标系,否则合并结果里会出现坐标乱跳的图层;一般用-t_srs统一指定输出坐标系。

合并完成之后必做一步自检:用ogrinfo查看合并图层的要素总数和属性字段列表。

ogrinfo -so -al /data/merged/江苏省全省.gpkg # 输出要素数(feature count)和字段列表;要素数应对得上各分片之和

如果要素数对不上,大概率是某个分片存在多部件几何被ogr2ogr忽略的情况,需要回查原始文件的几何类型。

5. 江苏省矢量数据应用避坑指南:这些坑我基本都踩过

5.1 裁剪后的图斑面积和原始图斑对不上

现象:裁剪输出后再用字段计算器算面积,结果和原图属性表里存的面积字段对不上,少则差 1%,多则差 20%。

原因:原属性表里的面积字段是用原始投影坐标计算的,裁剪后输出数据如果重新投影过,或者坐标系从高斯投影转成了地理坐标,面积字段是旧值不会自动更新。

解决:裁剪后重算面积字段。QGIS 里字段计算器填area($geometry)会按数据当前坐标系计算,如果是地理坐标(度),算出来是平方度,必须用transform($geometry, 'EPSG:4490', 'EPSG:4526')转成投影坐标后再算。我现在一般在裁剪流程里强制统一输出为高斯投影,面积字段直接等于area($geometry),不要再依赖原属性。

5.2 两个来源的相邻乡镇边界之间出现缝隙或重叠

现象:把甲县和乙县的边界图层放进同一张图,交界处要么有细长缝隙,要么互相重叠十几个平方米。

原因:相邻县的数据分别由不同测绘单位采集,各自成图时接边没有做拓扑一致处理,这条缝隙是先天存在的,不是投影转换产生。

解决:如果做全域汇总,得用拓扑修复工具而不是手动移动节点。QGIS 处理拓扑错误的路径是“处理 -> 矢量几何 -> 修复几何”,能处理部分几何错误,但对跨图层的接边缝隙需要用native:snapgeometries按容差做吸附。对制图用途来说更快的做法是接受这条细缝,出图不放大到 1:5000 以上基本看不出来。对面积统计用途来说必须处理,否则每个县交界处都会出现一块“无主之地”。

5.3 .prj 文件存在但坐标系是错的:拷数据时顺手带错了同名文件

现象:图层和数据位置都对,但拖到地图上整体偏移几百公里,查看.prj发现写的是EPSG:4537(那是新疆用的投影),可在江苏用明显不对。

原因:网上流传的压缩包里,整理者把不同省份的素材放在一起,文件名相同但投影坐标文件张冠李戴,数据本体是江苏,注释文件却是别处的。

解决:不要盲信.prj文件内容,每拿到一批新数据就要抽样比对实际坐标范围和属性里的典型字段。用ogr2ogr -t_srs转换之前,先跑一次ogrinfo看数据范围:

ogrinfo -so -al /data/某图层.shp | grep "Extent" # 江苏范围为东经约 116.3-121.9 度,北纬约 30.7-35.1 度(或投影坐标对应数值) # 如果范围差到十万八千里,prj 一定有问题

5.4 大范围合并后内存爆炸,电脑直接卡死

现象:对全省地类图斑做合并或空间连接,QGIS 跑到一半崩溃,或者把内存占满后系统无响应。

原因:shapefile 本身引擎效率有限,全省数据几千万元素直接叠空间分析,内存占用会指数级上涨。这是数据量的问题,不是代码写错了。

解决:大范围操作先做区域分块,分别处理再把结果追加合并。我一般用ogr2ogr -spat按经纬度范围做空间过滤,分东西两块跑:

# 只处理江苏东部范围,降低单次计算量 ogr2ogr -f GPKG /data/east_part.gpkg \ /data/merged/江苏省全省.gpkg \ -spat 119.5 30.7 121.9 35.1 # -spat 顺序是 minx miny maxx maxy,这里提取东半部分

处理完两个分块后再用追加写入的方式合并,这样任何一次操作的数据量都在可控范围内。或者干脆换用 PostGIS 来做,空间索引加持下同样查询会快几个量级,代价是得先导数据。

5.5 shp 属性表打开后“字段名全被截断”

现象:在 QGIS 或 ArcGIS 里打开属性表,长字段名变成 “DLTBM” 后面跟一串下划线数字,或者干脆认不出来。

原因:shapefile 的 DBF 格式规定字段名最长 10 字节,超过的部分会被强制截断,这不是某个软件故意破坏,而是格式限制。

解决:尽早放弃把 shapefile 当成果格式,转成 GeoPackage 保存,字段名完整且不会出现截断问题。导出的命令很简单:

ogr2ogr -f GPKG /data/final/江苏省数据.gpkg /data/source/某原始.shp

转完记得用ogrinfo复查一遍字段名和类型,因为部分软件在读取 dbf 时对中文字段名的字节计算方式不统一,原本正常的中文名也可能在转换后变成乱码。

6. 进阶用法:把矢量数据接进 PostGIS 做空间查询,比桌面软件顺手太多

桌面 GIS 处理完的江苏省矢量数据,如果只是画图就到此为止;如果想做“查找某个点 3 公里范围内所有地类图斑”“统计某条河流穿过几个区县”这类空间查询,PostGIS 比 QGIS 的表达式系统快得多。把整理好的 GeoPackage 导入 PostGIS 是最后的收尾动作,也是展开复杂分析的地基。

# 导入 GeoPackage 到 PostGIS,指定数据源 SRID 为 4526 ogr2ogr -f PostgreSQL PG:"host=127.0.0.1 user=postgres dbname=gis password=xxx" \ /data/final/江苏省数据.gpkg \ -nln jiangsu_dl \ -nlt PROMOTE_TO_MULTI \ -lco GEOMETRY_NAME=geom \ -lco FID=id \ -s_srs EPSG:4526 -t_srs EPSG:4526

-nlt PROMOTE_TO_MULTI是把各种几何类型统一提升为 MultiPolygon,避免后续空间查询因几何类型混用报错;-lco GEOMETRY_NAME指定几何字段名,后续 SQL 写起来更顺手。导入完成后执行一次空间索引的创建,这一步不是可选项:

CREATE INDEX ON jiangsu_dl USING GIST (geom);

没有这个索引,全表几百万个图斑叠加查询会慢到让人怀疑数据库是不是死了。索引建好后,像“统计每个区县的建设用地面积”这类常用需求就是一条 SQL 的事:

SELECT xzq.name, SUM(ST_Area(ST_Intersection(xzq.geom, dl.geom))) AS area_built FROM jiangsu_xzq xzq JOIN jiangsu_dl dl ON ST_Intersects(xzq.geom, dl.geom) WHERE dl.dltbm LIKE '2%' GROUP BY xzq.name;

这里ST_Intersects是粗筛,配合空间索引能迅速找出可能相交的要素,ST_Intersection才是精确求交。注意这一句如果图斑量极大,建议改成先按区县边界裁剪再做面积计算,否则ST_Intersection本身计算开销仍不小。我自己的经验是:空间分析一旦要用“循环遍历”的思路,就该换成数据库 SQL 而不是继续写 Python 逐要素跑——后者在小数据量上毫无问题,但江苏全省千万元素级别的数据,脚本跑上两小时比数据库十几秒出结果要慢出几条街。

这套从“解压 -> 体检 -> 统一坐标 -> 裁剪合并 -> 入库”的流程走完一遍之后,后续所有项目里这套底图都能直接复用,不需要每次重头折腾数据。唯一要承认的是数据维护是长期事,不同批次拿到的压缩包内部结构和坐标系永远有出入,保留一份“原始数据特征记录表”是我个人的习惯:每一批数据记录文件名、坐标系、比例尺、要素数量和已验证的问题,下次再碰到类似压缩包能直接对照着处理,这套方法论和具体数据本身一样值钱。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询