无锡乡镇街道shp数据包:shapefile解析、坐标转换与GIS数据处理指南 简介这份无锡市乡镇街道级矢量地图资源面向GIS开发、城市规划与空间分析人员提供无锡各区县与乡镇街道的行政区划边界数据可直接用于地图绘制、区划统计、可视化展示或空间分析。压缩包共含21个文件涵盖shp几何数据、dbf属性表、shx空间索引、prj投影坐标及xml元数据等完整配套格式并额外整理区县与乡镇两级shp文件方便按层级调用包体仅275KB轻量高效适配ArcGIS、QGIS等常见平台。数据包含县区和乡镇两类图层属性字段附有地名信息便于关联业务数据。目前已有526人学习使用数据经过整理校验若使用中遇到问题可协助处理。资源适合需要快速获取无锡基层行政边界、开展地理数据可视化或作为研究底图的读者能够节省自行搜集与配准的时间提升开发与制图效率。1. 无锡乡镇街道 shp 数据包解决的不止是“找文件”做城市尺度的项目时区县级边界通常不够用。社区网格、15 分钟生活圈、土地利用现状分析往往要求到乡镇街道一级。我接过好几个需求对方拿到的无锡边界要么是市级轮廓要么是网上拼来的区县边界精度参差不齐。这个压缩包里同时包含无锡各乡镇街道和区县两个层级的 shapefile还有配套的 prj、dbf、shx 等文件意味着不需要再从天地图或统计年鉴里逐条描边界。适合正在写规划论文、做 GIS 课程设计或者要在 BI 工具里做行政区划图的人。前提是得弄清坐标系和属性字段否则后续叠路网、叠人口栅格都会错位。2. shapefile 伴生文件与坐标系判读拿到手先别急着拖进地图2.1 从 .prj 到 .shp.xml每个伴生文件都是线索shapefile 不是一个单文件后缀而是一个由 .shp、.shx、.dbf、.prj 等组成的文件族。这个压缩包里的文件对应得很整齐无锡各乡镇.shp配的是无锡各乡镇.dbf、无锡各乡镇.shx、无锡各乡镇.prj、无锡各乡镇.sbn、无锡各乡镇.sbx、无锡各乡镇.shp.xml。无锡各区县.shp也有一整套同时还有一份无锡.shp作为全市范围轮廓。下面对照文件后缀说明各自的作用。后缀作用这个包里对应的文件.shp保存几何坐标和要素类型无锡.shp、无锡各乡镇.shp、无锡各区县.shp.dbf保存属性字段每行对应一个要素无锡.dbf、无锡各乡镇.dbf、无锡各区县.dbf.prj保存坐标参考系统的 WKT/ESRI 字符串无锡.prj、无锡各乡镇.prj、无锡各区县.prj.shx几何索引用于快速定位无锡.shx、无锡各乡镇.shx、无锡各区县.shx.sbn / .sbxArcGIS 生成的空间索引无锡.sbn、无锡.sbx 等.shp.xml元数据记录来源、坐标系和时间无锡.shp.xml、无锡各乡镇.shp.xml 等.sbn和.sbx是 ArcGIS 在做空间索引时生成的QGIS 和大多数开源库都不依赖它们缺了也能读如果有说明这份数据曾经在 ArcMap 里被打开并校验过可信度会高一些。.shp.xml里一般用 ESRI 元数据格式记录字段含义和生成时间文本打开可以看到EsriCreaDate这样的节点。我拿到压缩包的第一件事是先把 .prj 和 .shp.xml 都读一遍而不是直接拖图层。2.2 坐标系判读与常见误用用文本编辑器打开 .prj内容大致是两种形态要么是 ESRI 的PROJCS字符串要么是 OGC WKT 的GEOGCS块。无锡在 WGS84 下的经度范围约东经 119.5° 到 120.5°纬度北纬 31.4° 到 31.7°。如果 .prj 里的坐标系是GCS_WGS_1984那数据就是经纬度如果出现PROJECTION[Transverse_Mercator]或CGCS2000_3_Degree_GK_CM_120E那就说明是投影坐标单位是米。用命令行快速查看# 打印 prj 文件内容确认坐标系 WKT 字符串 cat 无锡各乡镇.prj这里cat直接输出坐标系字符串重点看三点GEOGCS里的基准面名称、DATUM是D_WGS_1984还是D_China_2000以及是否存在PROJECTION和UNIT[metre]。很多从网上下载的“镇街 shp”.prj 是空的或写的是GCS_Unknown这种情况软件会把坐标当作经纬度显示但实际可能是地方坐标系叠到遥感影像上会偏移几十米到几百米。最简单的验证办法是加载一份已知正确的底图比如天地图影像看边界是否吻合。投影坐标和地理坐标的混用是行政区划数据最常见的坑。投影坐标直接算面积、生成渔网、做缓冲区都可以用米经纬度则需要用estimate_utm_crs或类似方法转投影否则计算出来的面积单位是平方度完全不能看。在 QGIS 的图层属性里看到 CRS 是 EPSG:4490CGCS2000 地理坐标系或 EPSG:4326并不代表数据错了只代表你是用经纬度展示真正做分析前要再投影到适合无锡的 Gauss-Kruger 带。2.3 用 pyogrio 快速读取属性与几何信息直接拖进 QGIS 看属性当然可以但写脚本能得到更确定的结果。我常用pyogrio读取它的读写速度比传统geopandas默认引擎快而且能直接拿到 CRS 和几何类型。以下代码可以在 Jupyter 里逐行跑import pyogrio path 无锡各乡镇.shp # 读取元信息不加载几何速度很快 info pyogrio.read_info(path) print(info[crs]) # 输出坐标系对象None 就要警惕 print(info[geometry_type]) # 应该输出 Polygon 或 MultiPolygon print(info[fields]) # 列出所有属性字段名和类型 # 读取完整 GeoDataFrame用于后续筛选 gdf pyogrio.read_dataframe(path) print(gdf.columns.tolist()) print(gdf.head(3))这段代码先通过read_info拿到 CRS、几何类型和字段列表不加载几何数据文件大也能秒回然后read_dataframe把要素读成 GeoDataFrame方便看前几行和字段结构。尤其要看镇街名称字段到底叫XZQMC、town还是NAME同一个来源的数据字段命名习惯不同后面写筛选表达式时用错字段名会直接报 KeyError。再看字段类型print(gdf.dtypes) if XZQDM in gdf.columns: # 行政区划代码转成字符串截取前6位作为区县代码 code gdf[XZQDM].astype(str).str[:6] print(code.unique())这里.astype(str)是关键。很多 shp 的行政区划代码在 dbf 里被存成整数或浮点数比如320205会变成320205.0如果直接做字符串匹配就会漏掉所有乡镇。截取前6位可以识别区县滨湖区是 320211新吴区是 320214这样后面用区县代码关联各乡镇数据时就不会出错。3. 属性筛选、层级匹配与 shp 导出实战3.1 用字段筛选出指定镇街拿到数据后最常见需求是“只要某几个街道”。在 QGIS 中可以直接打开属性表用表达式筛选。如果字段名是XZQMC表达式就是XZQMC LIKE %华庄%这条 SQL 表达式会在字段XZQMC中模糊匹配包含“华庄”的记录选中后右键图层可以导出“保存所选要素”。但从重复性任务角度看用 Python 脚本更稳定特别是需要按一批名称筛选时。例如筛选华庄、雪浪两个街道import geopandas as gpd gdf gpd.read_file(无锡各乡镇.shp) # 用正则匹配街道名称两个名称用 | 分隔 selected gdf[gdf[XZQMC].str.contains(华庄|雪浪)].copy() selected.to_file(华庄雪浪.shp, driverESRI Shapefile, encodingutf-8)代码中str.contains默认支持正则华庄|雪浪表示包含任意一个即通过.copy()避免后续修改影响原数据。to_file里的encodingutf-8是为了让 dbf 里的中文在 Excel 里不乱码如果编码有误下次打开属性表会看到一堆问号。这里对应很多人在“shp 文件下载”之后的第一类需求本质是属性筛选不涉及空间裁剪如果要按范围裁剪应该用clip操作。3.2 区县与乡镇的层级匹配包里既有无锡各区县.shp也有无锡各乡镇.shp做统计时经常需要把乡镇挂到所属区县上。最直接的是属性表里如果有区县代码字段直接用left join。如果没有就需要用空间连接。常见做法是用sjoin先做相交再处理边界归属towns gpd.read_file(无锡各乡镇.shp) counties gpd.read_file(无锡各区县.shp)[ [XZQMC, geometry] ].rename(columns{XZQMC: 区县名}) # 用空间连接给乡镇加区县属性 joined gpd.sjoin(towns, counties, howleft, predicateintersects) print(joined[[XZQMC, 区县名]].head())sjoin的predicateintersects会判断乡镇面与区县面是否相交index_right是右侧表命中的索引可以用来关联区县名称。边界上的乡镇可能出现同时命中两个区县的重复行这时最好用质心归属法来保证每个乡镇只属于一个区县# 用乡镇质心落在哪个区县内来确定归属 towns_copy towns.copy() towns_copy[geometry] towns.geometry.centroid joined_point gpd.sjoin( towns_copy, counties[[区县名, geometry]], howleft, predicatewithin, )这里先复制一份数据再把 geometry 替换为质心随后用within找包含该质心的区县。sjoin的how保持left这样不会有乡镇因为质心稍微越过边界而丢失。需要注意的是质心法可能把狭长乡镇归错如果乡镇形状特别不规则建议结合centroid和representative_point两个结果对照。实际上对于同一套底图切割出来的区县和乡镇边界完全吻合直接用属性代码关联更稳空间连接只是兜底方案。3.3 导出为 KML、GeoJSON、TXT 的常用参数很多场景并不直接用 shpWeb 前端要 GeoJSON导航软件要 KML批量导入数据库要 TXT/CSV。用 GDAL 自带的ogr2ogr可以一次完成# 输出为 GeoJSON并强制转成 WGS84 经纬度 ogr2ogr -f GeoJSON 无锡乡镇.geojson 无锡各乡镇.shp -t_srs EPSG:4326 # 输出为 KMLGoogle Earth 可直接打开 ogr2ogr -f KML 无锡乡镇.kml 无锡各乡镇.shp # 属性表导出为带坐标的 TXT逗号分隔 ogr2ogr -f CSV 无锡乡镇.txt 无锡各乡镇.shp -lco GEOMETRYAS_XY这三行命令分别处理不同输出格式。-t_srs EPSG:4326表示输出坐标参考系统避免 GeoJSON 里残留投影坐标-f KML不需要指定-t_srsKML 标准强制经纬度-lco GEOMETRYAS_XY是 CSV 的图层创建选项它会在每行末尾追加 X 和 Y 坐标。网上常见的“shp转txt”多数情况用的就是这个命令但请注意这样导出的 TXT 只保留属性加坐标点并不包含面边界如果后续要画完整的多边形应该用 GeoJSON 或 GeoPackage。顺便说一句如果需要 shp 批量转 KMLShell 循环就能搞定for f in *.shp; do # 去扩展名后生成同名 KML 文件 name$(basename $f .shp) ogr2ogr -f KML ${name}.kml $f done循环里用basename去掉后缀再拼接.kml避免文件名重复ogr2ogr每次都独立读入一个 shp输出对应的 KML。如果文件很多Windows 下建议在 Git Bash 或 WSL 里运行避免批处理转义问题。输出格式driver 名称关键参数典型用途GeoJSONGeoJSON-t_srs EPSG:4326Leaflet / ECharts 渲染KMLKML无输出经纬度Google Earth、导航设备CSV/TXTCSV-lco GEOMETRYAS_XY报表、数据分析GeoPackageGPKG-nlt PROMOTE_TO_MULTI本地地图包、PostGIS-nlt PROMOTE_TO_MULTI在转 GPKG 时推荐加上因为 shapefile 允许 Polygon 与 MultiPolygon 混存而部分数据库或后端不接受混合几何强制提升为 MultiPolygon 后能避免导入 PostGIS 时报 “Geometry type mismatch”。4. 无效几何排查与批量压缩、转 3dtiles4.1 先查拓扑再谈转换许多行政区划 shp 在人工编辑边界时会产生自相交、重复顶点、无效环等问题。直接拿去转 GeoJSON 还能用但转 3dtiles 或做空间计算时会出现空洞、面积异常。先用ogrinfo快速确认几何类型# -so 只输出图层摘要过滤出几何类型行 ogrinfo -so 无锡各乡镇.shp 无锡各乡镇 | grep Geometry这条命令输出几何类型如果显示Polygon是正常的如果出现Geometry Collection或空值就要小心了。更严格的自相交检测要用 GEOS 的is_validimport geopandas as gpd gdf gpd.read_file(无锡各乡镇.shp) # 找出无效几何并统计数量 invalid gdf[~gdf.geometry.is_valid] print(invalid.shape[0], 个无效几何) # 用 buffer(0) 重建有效几何修复自相交 gdf[geometry] gdf.geometry.buffer(0) print(gdf.geometry.is_valid.all())buffer(0)是修复 shp 无效几何的经典做法它会把自相交环重新构建为有效多边形代价是可能抹掉极小缝隙。执行后再用is_valid.all()确认是否全部恢复。这一步对后续 shp 转 3dtiles 很关键因为 3dtiles 要求闭合且无重叠自相交面会在三角化过程中报错。如果无效要素数量很多建议先gdf gdf[gdf.geometry.is_valid]剔除坏数据不要盲目修复。常见几何错误与处理方式如下表错误类型现象处理办法自相交Self-intersectionis_validFalse转 KML 出现破损buffer(0)重复顶点面积统计无异常但渲染错乱QGIS 的 Delete Duplicate Geometries缝隙相邻面之间有空白Union/ fill gaps混合几何Polygon 和 MultiPolygon 混用-nlt PROMOTE_TO_MULTI或dissolve表格中列出的四类问题里混合几何最容易在导出时爆错因为它不是拓扑错误而是类型问题。处理方式可以统一转 Multi也可以在导出时由 GDAL 自动提升。4.2 单个 shp 如何批量压缩行政区划 shp 即使一个乡镇只有几百个顶点整个无锡的文件也可能到几十 MB。发布为地图服务前通常要做节点简化。用mapshaper能快速简化边界# 使用 Douglas-Peucker 算法保留约20%的节点 mapshaper 无锡各乡镇.shp -simplify dp 20% -o 无锡乡镇_simplified.shpdp指定算法20%意思是保留 20% 的节点数。简化后视觉上几乎不变但文件体积大幅下降。需要注意简化算法不感知拓扑多个相邻镇街各自简化后可能出现微小缝隙矢量切片服务会容忍但做面积统计时不要用简化后的数据。如果要一次处理多个 shp用 Shell 循环for f in *.shp; do # 提取不带扩展名的文件名 name$(basename $f .shp) mapshaper $f -simplify dp 30% -o out/${name}_simplified.shp done这个循环会把当前目录所有 shp 文件逐个简化输出到out目录basename用于去掉扩展名避免拼接文件名时重复.shp.shp。批量压缩后的文件可以直接发布为本地图层包也可以再转成 GeoPackage 这种单文件格式来管理。4.3 从 shp 到 3dtiles 的典型链路网上经常看到“shp转3dtiles”的需求。直接转 3dtiles 的工具其实都走了同一条中间路径先把 shp 转成 GeoJSON再用 Cesium 相关工具或pg2b3dm切瓦片。步骤通常是# 第一步shp 转 GeoJSON统一用 WGS84 经纬度 ogr2ogr -f GeoJSON 无锡乡镇.geojson 无锡各乡镇.shp -t_srs EPSG:4326 # 第二步用 3d-tiles-tools 生成 3dtiles 瓦片目录 npx 3d-tiles-tools --input 无锡乡镇.geojson --output 无锡乡镇_3dtiles这里的第二步依赖 Node.js 环境npx会自动下载工具。参数上要注意输入 GeoJSON 必须是经纬度且要素类型必须统一为 Polygon不能把 MultiPolygon 混在一起否则工具会报 “unsupported geometry type”。所以转换前先做dissolve或统一提升为 MultiPolygon。另外如果只是做可视化不需要真的转 3dtiles可以先转成 GeoJSON 用 Mapbox 加载性能差别不大3dtiles 更多是给 Cesium 场景或大体量数据用。4.4 与其他空间数据叠加时的坐标系对齐做道路分析时网上搜来的“2020全国道路shp下载”“遥感道路shp文件”大多是 WGS84 或 Web Mercator 投影而行政区划可能是 CGCS2000 或西安80。不能直接叠加必须先统一 CRS。我的做法是先把道路数据转到乡镇数据的坐标系# 将道路数据转换为 CGCS2000 地理坐标系 ogr2ogr -t_srs EPSG:4490 道路_cgcs2000.shp 道路.shpEPSG:4490 是 CGCS2000 地理坐标系和 WGS84 在无锡区域差异只有几十厘米如果只是叠加展示可以忽略但和栅格做像元统计时最好转到当地投影坐标比如 EPSG:4538CGCS2000 / 3-degree Gauss-Kruger CM 120E这样面积计算才准确。生成渔网分割 shp 时也一样先统一 CRS 再切否则网格和边界会互相偏移。地下水位栅格这类数据自带的 .prj 往往也是经纬度用read_csv读出来再转 GeoDataFrame 时要显式设置 CRS否则默认为 None后续空间操作直接报错。5. 验证一份镇街边界数据是否可信的三个土办法5.1 叠合影像看边界是否“贴”着建成区将无锡各乡镇.shp加载进 QGIS底图选择 XYZ Tiles 中的天地图影像。正常情况下乡镇界应该沿着河道、公路中心线或山脊延伸和影像上的明显地物重合。如果边界与影像中村庄边缘交叉错乱说明数据经历了不正确的坐标变换或者数字化精度不足。验证时把图层透明度调到 50%对比 1:50000 视图下的吻合程度即可。5.2 拓扑自检检查重复和缝隙使用 QGIS 的 Topology Checker 插件添加must not have gaps和must not have duplicates规则到乡镇层。无锡乡镇边界应是无缝铺满全区任意两个乡镇之间不应有空隙有缝隙说明数据在裁剪时丢失了窄带区域。处理办法是用fill gaps工具把缝隙分配到相邻要素或者回到buffer(0)修复。对“无锡各区县.shp”也要用同一套规则检查因为区县边界应完全贴合乡镇外边界。5.3 面积对齐和统计年鉴比大小一个简单有效的验证方法是把乡镇面积和统计公报中的面积对比。用 SQL 查询到每个乡镇的面积即可-- 将几何转成 geography 计算平方千米面积 SELECT name, ST_Area(geom::geography) / 1000000.0 AS area_km2 FROM wuxi_towns ORDER BY area_km2 DESC;这里把几何转成geography是为了在数据库中直接得到以米为单位的面积结果除以 1000000 得到平方千米。如果直接在平面坐标系下用ST_Area(geom)返回结果取决于坐标系单位可能是度不是米。对比时允许 1%~2% 的误差超过 5% 需要考虑是否有区域归属争议或数据扫描变形。另外用统计年鉴的户籍人口做离线检查时可以用乡镇面积乘以平均人口密度大概判断但不要反过来用面积去反推人口那会掩盖内部差异。本文还有配套的精品资源点击获取