ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

shp数据从获取到转换全流程实战:以大理州行政区划为例

shp数据从获取到转换全流程实战:以大理州行政区划为例 简介在GIS数据交换中shapefileshp作为最通用的矢量格式广泛用于行政区划边界存储与可视化。其本质是由多个文件构成的集合其中.shp存储几何、.dbf存储属性、.shx提供索引而.prj与.cpg分别记录坐标系与字符编码。理解这些底层原理能有效规避图层打不开、属性乱码、图形偏移等高频问题。实际工程中针对区县级行政边界如大理州12个区县的数据获取、校验、拆分合并及格式转换是数据工程师和GIS开发者的常见需求。从数据源选择、属性表检查到坐标系定义再到批量转换为3dtiles、CAD、GeoJSON等下游格式一套标准化的处理流程可大幅提升效率。掌握基于QGIS、ArcGIS及Python geopandas的工具链配合对cpg编码和投影坐标的排查技巧能轻松应对跨平台数据交换场景。 做 GIS 项目最常碰到的第一道坎往往不是算法设计也不是服务器部署而是数据本身。我两年前接了一个云南方向的可视化需求对方开口就说你先拿大理州各区县的行政区划 shp 做一张底图。当时我手头只有全国分省数据偏偏缺按区县拆分的细粒度边界。后来几天时间从数据来源、打开工具、属性表处理到改成各种格式给下游用我把大理州 12 个区县的 shp 数据从获取到转换整个流程完整踩了一遍才发现这种看起来不就是个区划文件嘛的 shp实际用起来到处都是坑。这篇文章就把这套处理流程里最实用的部分一次性讲明白。核心围绕大理州各区县行政区划 shp 文件的文件结构、获取渠道、读取方式、拆分合并、格式转换以及避坑经验展开。不管你是刚接触 GIS 的新人还是被 shp 的编码和坐标系折腾过几次的老手这套方法论换成其他州市、其他区县级数据一样能照搬。1. shp 到底是个啥一堆文件搭伙过日子很多人第一次接触 shp习惯把它当成一个文件来理解然后就会出现为什么我拷走一个 .shp到别的电脑就打不开了这种灵魂拷问。实际上shapefileshp不是单个文件而是一组配套文件的集合。理解这一点后面遇到各种打不开、乱码、坐标系漂移至少能先有个排查方向。1.1 shp/dbf/shx 是铁三角谁缺了都尴尬一个完整的 shapefile 至少包含三个基础文件.shp、.shx、.dbf。这三个文件各干各的活.shp存储几何信息也就是点、线、面的坐标数据是图形本身。.shx存储几何索引作用是让软件快速定位到某条几何记录。它不直接画图但就像一个目录。.dbf存储属性表每一行对应一个要素记录名称、代码、面积等信息。格式是经典的 dBase 数据库表。用一个生活化的类比shp 是户型图dbf 是住户登记表shx 是楼层索引目录。三者一起才能完整描述这一户是谁、长什么样、住几楼。实际使用中最常见的翻车情况是从项目文件夹里单拷了一个 .shp 文件到 U 盘到另一台电脑打开就报错无法识别文件或者图层是空的。因为你漏了 .shx 和 .dbf。更有意思的是有些软件能容忍缺 .shx但极慢缺 .dbf 的话图形能显示但所有属性全为空区县名字全部消失缺 .shp 那就不用说了游戏直接结束。所以拿到任何 shp 数据第一件事就是确认这三个基础文件是否齐全。如果别人发你的压缩包里只有一个 .shp先别急着骂对方检查一下是不是邮件或网盘把这个多文件集合当成了碎片文件自行过滤了。1.2 prj 和 cpg这两个小跟班最容易被忽略铁三角之外还有两个经常一起出现的文件虽然名字不起眼但往往决定你的数据能不能用对。.prj 文件存储坐标系和投影信息。如果打开 shp 时软件弹窗提示未知空间参考或缺少投影信息基本就是没有 .prj 或 .prj 损坏。没有坐标系信息数据在软件里就会默认按无坐标系处理叠加别的图层时极容易出现位置错乱。比如明明是 CGCS2000 投影坐标的数据软件按 WGS84 经纬度读取图形会异常拉伸甚至跑到海里。.cpg 文件记录字符编码常见内容是 UTF-8 或 GBK。它不在铁三角里但丢了以后属性表里的中文大概率会变成乱码。这个文件的内容极其简单往往就是一行文字。比如UTF-8我见过不少人手动创建一个 .cpg 文件内容写 UTF-8问题就解决了。所以 cpg 不是可有可无的摆设它是属性表中文能否正常显示的关键。另外还有一些附加文件比如 .sbn/.sbx空间索引、.qpjQGIS 的投影辅助文件、.xml元数据。这些丢了基本不影响打开但 .qpj 偶尔会影响 QGIS 的坐标系识别好在新版 QGIS 都会自动读取 .prj 并生成 .qpj。1.3 一个区县 shp 的属性表里通常有什么以大理州各区县行政区划 shp 为例打开属性表后一般会看到这些字段NAME 或 XZQMC区县名称比如大理市祥云县宾川县。XZQDM 或 PAC行政区划代码每位数字都有含义可以用它关联统计年鉴、人口数据等外部表。SHENG / ZHOU所属省、州有时数据源层级清晰的话会附带。AREA 或 SHAPE_Area要素面积注意不同数据源单位可能不同有的是平方米有的是平方千米甚至有些是投影平面面积而非椭球面积。这里我特别建议确认一下数据的行政区划代码是否和现行标准一致。因为区划代码会随着撤县设区、县界调整而变动旧数据可能还保留着已经废止的代码。哪怕是官方发布的数据也存在更新滞后使用时最好以最新公布的代码为准做个抽样比对。在实际项目里我曾经拿到一个大理州的 shp 文件属性表里只有图形没有名称字段全靠一个数字代码撑着。这种情况下也不要慌如果代码字段完整可以写一段 Python 脚本用代码字典把名称字段补全。但如果没有代码字段、也没有名称字段这块数据就基本废了只能重新找来源。2. 先把手头没有的数据弄到手获取与校验这个标题放在哪都是热门搜索因为它戳中了一个痛点网上有大量云南省县域轮廓 shp某某市行政区划 shp但是真正能保证数据准确、坐标规范、字段完整的并不多。我可以给你几个实践下来比较靠谱的渠道再说说下载之后应该怎么校验。2.1 靠谱的数据渠道渠道这个东西不能只知道一个因为很多平台会调整下载策略。我常用的有三个方向第一类是官方公开地理数据平台。比如全国地理信息资源目录服务系统提供 1:100 万公众版基础地理数据里面包含县级行政区域面。这类数据权威性高属性字段规范但生产时间可能早一些县界不一定是最新的。第二类是互联网地图开放平台。比如阿里云 DataV.GeoAtlas提供了全国省市县级行政区划的 JSON 数据可以下载到单个区县或者整个地级市的边界数据。格式主要是 GeoJSON拿到手之后用 QGIS 或 Python 转成 shp 非常方便。这个路径适合做前端可视化项目速度快、免费、数据更新比较及时但坐标基准是互联网地图常用的国测局坐标带偏移不适合做专业测绘用途这一点稍后展开说。第三类是开源社区和 GIS 数据论坛。OpenStreetMap 可以导出全球的行政边界但精度和官方边界之间可能存在差异而且经过人工编辑不同区域的完成度不一样。各类 GIS 交流社区里也会有人整理和分享省市级行政区划数据包质量参差不齐需要自己核查。我的建议是如果是做正式项目、对边界精度和坐标基准有要求优先选择官方来源如果只是做可视化、展示型应用互联网平台的数据转换更轻量完全够用。2.2 下载后别急着用先做三件事我见过太多人下载完数据双击打开看到图形就以为万事大吉结果做到一半才发现坐标系不对、属性表缺字段回头返工。所以下载之后务必先花五分钟做三件事第一检查文件清单。压缩包解压后确认是否包含 .shp、.shx、.dbf、.prj 四个文件。如果缺 .prj后面十有八九要处理坐标系问题。第二用 GIS 软件打开查看属性表。确认有没有区县名称和行政区划代码字段字段值是否规范。比如大理州应该有 1 市 11 县共 12 个区县如果你的 shp 里只有 5 个要素那数据八成被裁剪过或不完整。第三查看坐标系。在图层属性里看单位是度地理坐标系还是米投影坐标系看参考椭球是 WGS84、CGCS2000 还是西安 1980。推荐用下面的表格检查检查项正常情况异常情况文件清单shp/shx/dbf/prj 齐全缺 prj 或 dbf后续处理成本极高要素数量大理州 12 个区县数量明显偏少大概率被裁剪名称字段大理市、祥云县等完整字段为空或乱码坐标系CGCS2000 / WGS84 / 地方投影无坐标系或混合坐标系属性编码中文正常显示乱码需要处理 cpg 文件以上任何一项不过关建议优先解决不要带着问题继续。2.3 如果你只有云南省的州界没有县级分割怎么办有些数据包只提供了云南省级轮廓没有大理州按区县拆分的面。这种情况我一般建议用两个思路解决第一直接去数据源找更细粒度版本。全国地理信息资源目录服务系统提供地市级和区县级的面数据可以精确筛选大理州。下载后按行政区代码或名称属性筛选出大理州下辖区县即可。第二如果只能拿到云南省县级边界数据那就自己切出大理州。具体做法是把云南省县级面数据和全国/云南的州界数据做空间相交或裁剪。QGIS 里的 Clip裁剪工具就能实现。先用州界把省界范围裁剪出大理州区域再用县界图层做相交最后按州名称 大理州过滤。这样处理出来的数据结构和你直接下载区县数据基本一样。这里有个细节注意行政区面和行政区界线是两种不同数据。面是填满整个区域的封闭多边形适合做底色和统计可视化线只包含边界线适合做样式更灵活的边界叠加。如果拿到的数据是线文件要先转成面文件QGIS 提供 Polygonize 工具否则后面做裁剪和相交会吃亏。3. 打开一个 shp 的正确姿势三种常用工具链拿到数据之后用哪种工具打开取决于你的项目场景。常见的有三条工具链ArcGIS / ArcGIS Pro、QGIS、Python。每一套都有它的优势和坑我分别说说。3.1 ArcGIS / ArcGIS Pro拖进去就行吗在 ArcGIS 里打开 shp 确实很简单直接把文件从文件夹拖到地图画布软件会加载为一个图层。但如果你是第一次打开且文件缺少 .prj软件会弹出提示框问未知空间参考这时你选择以 WGS84 打开只是这一次会话临时生效并没有修改文件本身。如果你的数据实际是 CGCS2000 投影坐标这一步就会埋下坐标系错误的隐患。正确做法是遇到未知坐标系的提示后先搞清楚数据原本的坐标系然后用定义投影工具给数据补上正确的坐标系信息再叠加其他图层。这样之后每次打开都是对的。ArcGIS Pro 和 ArcMap 在加载 shp 上的行为基本一致只是 Pro 在投影处理上更智能部分投影信息可以自动识别。不过 Pro 对机器配置要求高家庭电脑没装的话直接看下面两个方案。3.2 QGIS免费、跨平台的兜底工具如果你不想为偶尔一次打开 shp 专门装一个重型商业软件QGIS 是最合适的替代。它免费、跨平台、启动快对 shp 的兼容性几乎是最好的。QGIS 打开 shp 同样可以直接拖拽也支持图层-添加图层-添加矢量图层的常规操作。QGIS 在编码处理上比 ArcGIS 更透明。遇到中文乱码时可以右键图层-属性-源设置有一个数据源编码选项手动切换 UTF-8 或 GBK马上就能看到属性表恢复正常。这个功能在 ArcGIS 里反而没有这么直观cpg 文件丢失时你只能靠手动创建 cpg 文件或转编码。3.3 Pythongeopandas 是处理 shp 最省心的库用 Python 处理 shp我首选 geopandas其次才是 pyshp/shapely/fiona 这些底层库。geopandas 把数据读入 DataFrame 结构处理属性表、筛选、拆分、合并都特别顺手。安装方式建议用 conda因为直接 pip 安装 geopandas 时GDAL、Fiona 这些底层依赖很容易出现版本打架。我的建议是conda create -n geo python3.10 conda activate geo conda install geopandas读取大理州区县 shp 的代码非常简单import geopandas as gpd gdf gpd.read_file(dali_county.shp) print(gdf.shape) # 查看行数和列数 print(gdf.columns) # 查看字段名 print(gdf.crs) # 查看坐标系 print(gdf[[name, xzdm]].head()) # 预览关键字段如果只想快速画个图gdf.plot()这里要注意的一点是geopandas 读取 shp 时的路径尽量不要包含中文。Windows 环境下中文路径偶尔会触发编码异常明明数据没问题就是读不进去。把项目目录都改成英文能少踩很多坑。3.4 打不开或图层为空时按顺序排查加载 shp 图层为空或者完全打不开95% 的情况逃不出下面几个原因缺 .shx文件不完整图层可能加载成功但不显示内容。路径含中文尤其在 ArcGIS 和 Python 的 GDAL 环境下中文路径会引发读取异常。用文本编辑器打开过 shp 并保存了shp 是二进制文件用记事本打开再保存文件头被破坏整个文件就废了。几何数据损坏图形要素数异常但属性表正常这种大多数是源数据问题需要重新下载。排查顺序建议先看文件清单 → 再改英文路径 → 再用 QGIS 打开试试 → 最后检查 shp 文件大小是否异常小。这样一步步定位基本不会白折腾。4. 从全州一张图到任意区县组合拆分、合并与区域重组很多时候我们拿到的是一整张大理州区县图但项目只需要其中几个区县或者需要把每个区县单独存成一份 shp。这个章节就把拆分、合并、融合和网格化这些高频操作一次说透。4.1 按区县导出右键导出最直接如果你只需要某几个县最简单的方法是打开属性表选中相应要素再右键图层-数据-导出数据在弹出的对话框中勾选所选要素指定输出路径即可生成新的 shp。按属性选择时SQL 语句可以这样写NAME 大理市 OR NAME 祥云县 OR NAME 宾川县需要注意属性字段名如果是中文在 SQL 表达式里要用双引号括起来。有些版本的 ArcGIS 对中文 SQL 的解析不友好如果总报语法错误可以先看一下字段的别名是否存在冲突。QGIS 里操作也很方便右键图层-筛选输入同样格式的表达式然后选中筛选结果右键导出-保存所选要素为。4.2 批量一次性拆分ArcGIS 的 Split 工具如果要把大理州下辖 12 个区县全部一次性拆成 12 个独立 shp可以试试 ArcGIS 的 Split 工具。路径是分析工具-Analysis Tools-提取-Extract-Split。这个工具需要一个分割要素图层并指定一个字段作为拆分依据。比如把全州面数据作为输入用NAME字段做分割字段运行后会在输出目录里生成按每个区县名称命名的 shp 文件。实操中有两个坑必须提醒第一输出文件夹必须为空。Split 工具不会自动覆盖已有文件如果输出目录里已经有同名文件运行会直接报错。第二分割字段的值不能包含非法字符。假如某个区县名称里带了空格或特殊符号生成的 shp 文件名可能会异常。大理州的区县名称都是规范地名一般没有问题但如果你处理的是其他数据源建议先检查字段值。QGIS 里对应的工具叫拆分矢量图层Split vector layer在 Processing Toolbox 里直接搜索即可输入图层和唯一 ID 字段就能批量输出。4.3 Python 按属性循环拆分灵活度最高当数据字段复杂、输出要求多样时用 Python 写循环拆分是最灵活的。import geopandas as gpd from pathlib import Path gdf gpd.read_file(dali_county.shp) out_dir Path(dali_split) out_dir.mkdir(exist_okTrue) for name, group in gdf.groupby(name): # name 字段是区县名group 是当前区县的要素集合 group.to_file(out_dir / f{name}.shp, encodingutf-8)执行完会在 dali_split 目录下生成 12 个 shp 文件每个文件都带完整的属性表和坐标信息。这里的关键点是encodingutf-8参数它会在输出时自动生成对应的 .cpg 文件保证后续打开时中文不乱码。如果你需要按多个县合并输出比如东三县祥云、弥渡、宾川合并成一份可以先构造一个分组字典再用条件筛选。4.4 反过来合并多份县界拼成一张州图合并操作最常发生在两种情况一是手上有多个县的独立 shp想拼成大理州全州图二是从其他来源拿到的分块数据需要合成一张完整覆盖区域。ArcGIS 的合并工具Merge可以处理多个输入图层但有一个大前提各图层的字段结构最好一致。如果 A 县数据有NAME字段B 县数据却是XZQMC合并后字段会直接分开其中一个字段大量为空。这种问题可以通过字段映射功能手动对应但比较繁琐最好在合并前统一字段结构。QGIS 对应的工具是合并矢量图层Merge vector layers同样建议先用一个简单的脚本统一字段名和类型再合并。另外还有一个容易混淆的工具是融合Dissolve。Merge 是把多个文件合成一个文件Dissolve 是把一个图层里的多个要素按某个字段合并成一个要素。比如把 12 个区县面按州名称大理州字段融合成一张全州大面。这个操作在做区域底色、简化数据时非常常用。4.5 渔网分割把区县 shp 切成规整格子热搜词里有个渔网分割 shp用的是 ArcGIS 的创建渔网Create Fishnet工具。它的思路是生成一个覆盖研究区域的网格面再把网格面和区县边界做相交Intersect最终得到按县域边界切割后的规整网格。这个操作在人口分布统计、空间抽样、农业区划可视化的场景里很常见。比如估算大理州各县在不同格网尺度下的数据量就需要先有每个格子归属哪个县的空间判断结果。流程可以简化为三步用 Create Fishnet 生成网格网格范围设置为大理州 shp 的外包矩形。用 Clip 或 Intersect 把网格裁剪到州界范围。用空间连接把区县名称字段关联到每个网格上。实际操作中网格尺寸要根据你的研究尺度定比如 1km x 1km 或 10km x 10km。网格太小会生成海量要素电脑配置不够容易卡死网格太大又失去统计意义。建议先小范围试跑一次确认性能可以接受再全州执行。5. 高频转换全流程3dtiles、CAD、txt、KML 与 SketchUp 导入shp 格式虽然通用但下游环节经常需要其他格式热门搜索词里最集中的就是 shp 转 3dtiles、shp 转 txt、批量 shp 转 CAD、SketchUp 导入 shp。这一章把这几条转换路径和各自的坑完整拆开讲。5.1 shp 转 3dtiles平面数据如何在三维地球里显示3dtiles 是面向 Web 端三维场景的数据格式Cesium 生态用得最多。把大理州各区县行政区划 shp 转成 3dtiles核心思路并不是把矢量面变成三维模型而是给平面矢量数据赋予一个高度基准让它在三维地球上有正确的落位。我常用的工具是 CesiumLab它提供免费的格式转换功能界面操作也算友好。流程大概是这样先用 QGIS 把 shp 转成 GeoJSONCesiumLab 对 GeoJSON 的兼容性更好也可以直接拖入 shp但偶尔会出现属性字段丢失。打开 CesiumLab 的矢量转 3dtiles功能输入 GeoJSON 或 shp。选择高度模式。如果要让区县贴着地表显示选贴地模式如果要生成有厚度的立体柱状区域选拉伸并设置拉伸高度比如 500 米。设置坐标系。数据如果是 WGS84 经纬度CesiumLab 会自动识别如果是投影坐标系最好先转成 WGS84 再导入。导出后得到一个 tileset.json 为主的文件目录在 CesiumJS 中通过Cesium3DTileset加载即可。这里有一个实战建议做三维可视化前先用 QGIS 的简化工具Simplification对区县边界做一次抽稀。简化容差设置为几十米肉眼几乎看不出区别但瓦片生成体积和加载性能会有天壤之别。我处理过大理州的数据原始边界几万甚至几十万个节点简化后能降到几千个节点加载速度提升非常明显。另外如果你的开发栈是 ArcGIS ProPro 3.x 之后也支持直接导出 3D Tiles在共享面板里可以选择。这个方案对 ArcGIS 用户来说是最顺手的不需要额外装工具。5.2 批量把多个 shp 转成 CADDWG / DXF把 shp 转成 CAD 格式在设计院、规划院的协作中非常常见。大家拿到的往往是 DWG 或者 DXF而 GIS 侧输出最稳定的通常是 DXF。ArcGIS 里的路径是转换工具-转换为 CAD-导出为 CAD。它可以同时选择多个 shp 文件一次输出成一个 DWG 或 DXF。需要注意CAD 里没有 GIS 的属性表概念所以导出的图形只有几何轮廓和少量注记区县名称能不能显示成文字取决于是否需要设置注记映射。如果数据量比较大我更喜欢用 QGIS 配合命令行动手因为可以批量跑。安装 GDAL 之后可以用命令行ogr2ogr -f DXF output.dxf input.shp如果有多个 shp 文件在 Python 里循环调用即可。import subprocess from pathlib import Path for shp in Path(shp_dir).glob(*.shp): subprocess.run([ ogr2ogr, -f, DXF, fcad_output/{shp.stem}.dxf, str(shp) ])几个前车之鉴输出 DXF 版本最好选择 2010 或以上老版本 CAD 打开新版 DXF 有时会出现图元丢失。面要素转过去默认是闭合多段线如果 CAD 里需要独立的面对象可能要在 CAD 端再处理一次。中文注记经常出现乱码或丢失这个和字体映射有关建议导出前先确认 CAD 端的文字样式。5.3 shp 转 txt属性表和坐标提取热搜词里有个测定界 shp 转 txt 工具.tbx这是测绘领域比较细分的需求比如把界址点 shp 转成坐标点 txt 文件给全站仪或者平差软件用。更通用的场景是拿到一个点数据 shp需要把下面的点号、X 坐标、Y 坐标导出成 txt。在 ArcGIS 中可以先用添加 XY 坐标Add XY Coordinates工具给属性表增加 POINT_X 和 POINT_Y 字段然后右键属性表-导出选择 dBASE 表再转成 txt。但如果只是要一个简单文本用 Python 更快import geopandas as gpd gdf gpd.read_file(points.shp) with open(points.txt, w, encodingutf-8) as f: for idx, row in gdf.iterrows(): x, y row.geometry.x, row.geometry.y f.write(f{row[point_id]},{x:.6f},{y:.6f}\n)一个非常重要的细节是导出坐标之前先确认坐标系。如果是经纬度地理坐标系输出的数是带小数位的度如果是投影坐标系输出单位是米。不同坐标系输出的坐标数值差距非常大所以导出的 txt 一定在文件头注明坐标系否则下游交换时很容易出错。5.4 shp 转 KML / GeoJSON这两个格式在 Web 可视化中很常遇到。KML 是 Google Earth 和 Google Maps 常用的格式GeoJSON 则是各种前端地图库Leaflet、Mapbox、OpenLayers的标配。QGIS 的操作非常直接右键图层-导出-另存要素为格式选 KML 或 GeoJSON。注意 KML 对字段名和长度有要求属性字段最好用英文短名中文长字段名会生成一层嵌套的 Schema影响后续解析。如果使用 geopandas一行代码就能转 GeoJSONgdf.to_file(dali_county.geojson, driverGeoJSON, encodingutf-8)转 KML 的话geopandas 默认驱动可能不太好用我一般还是用 QGIS 或者 GDALogr2ogr -f KML output.kml input.shp还需要特别说明KML 默认以 WGS84 经纬度存储。如果源数据是投影坐标系转 KML 之前务必先重投影到 WGS84否则 Google Earth 里的位置会错得离谱。5.5 SketchUp 导入 shp 的曲线方案热搜词里su 怎么导入 shp这个问题也很典型。SketchUp 本身不直接支持读取 shp因为它是三维建模软件不是 GIS 工具。但实际工作中经常要把地形范围、建筑用地边界从 GIS 数据搬进 SketchUp 做体块推敲。我的做法是先用上一节的方法把 shp 转成 DXF然后在 SketchUp 里通过文件-导入选择 DXF 格式。导入成功后面会变成 SketchUp 里的闭合边线和面可以配合推拉工具生成三维体块。如果不想走 DXF还有一条路用插件。SketchUp 有一些收费或免费的 GIS 导入插件可以直接导入 shp 并保留部分属性但安装和稳定性比较看运气而且很多插件在较新版本的 SketchUp 里已经停止维护所以最稳的方案还是 DXF 中转。转换时有一点要注意shp 里如果包含高程比如地形等高线DXF 导入 SketchUp 后会自动按 Z 值生成三维线。如果只有二维面导入后就是平面图形需要手动在 SketchUp 里拉高度。6. 那些让我炸毛的坑cpg、坐标系、字段名和文件大小最后一章专门讲坑。这些坑我在处理大理州区县数据时几乎全踩过有些坑甚至能让人昏天黑地排查一整天。把这几个问题讲透比你多装十个软件都管用。6.1 cpg 文件丢失导致的乱码问题热搜词里有个问题问得很具体shp 文件导出的时候没有 cpg 文件是怎么回事。这个问题背后的原因有三类第一源数据本身就没有 cpg 文件。很多从老系统、专业仪器导出的数据压根没生成过 cpg。第二命令行工具导出时没有自动写 cpg。部分 GDAL 版本或第三方库默认不生成 cpg导致输出的 shp 没有编码标识。第三ArcGIS 中文系统的默认编码是 GBK 或 GB2312导出的 dbf 文件用 GBK 存储字符串但如果不生成 cpg其他软件读取时只能猜测编码猜错就是乱码。解决思路也简单最直接的是手动创建 cpg 文件。比如你的文件是 dali_county.shp就新建一个 dali_county.cpg内容写UTF-8或GBK保存为无 BOM 的纯文本放在同一目录下。如果需要批量修复用 Python 一行脚本就能搞定from pathlib import Path for shp in Path(.).glob(*.shp): cpg shp.with_suffix(.cpg) # 如果源数据是UTF-8就写UTF-8是GBK就写GBK cpg.write_text(UTF-8, encodingutf-8)有一种更稳妥的方式不要手动修改原始文件而是用 QGIS 打开乱码数据在数据源编码里切换正确编码然后另存为一个新的 shp并在保存时设置编码为 UTF-8。这样新的输出一定会带 cpg以后不管在哪里打开都不会乱码。6.2 坐标系错乱为什么图形出现在大海里坐标系问题在 shp 数据交换中最常见而且报错方式极具迷惑性图层能打开、属性表正常、图形形状也对但位置就是不对比如整个大理州跑到印度洋中间。这种情况通常是两种原因叠加一是数据没有 .prj 文件软件按默认的无坐标系或 WGS84 读取。如果这个数据的实际坐标是投影坐标比如 CGCS2000 3 度带高斯投影数值是 500 万级别的米数被当成经纬度显示后地图范围变成东经 500 万度当然不可能落在正确位置。二是定义投影和投影转换搞混了。在 ArcGIS 中定义投影Define Projection只是给数据贴一个坐标系标签不改变坐标数值投影Project才是真正的坐标转换。很多人拿到无坐标系数据直接用了 Project 工具结果报错或者结果完全不对。正确顺序是先定义投影再投影转换。QGIS 里对应的操作是重投影图层Reproject layer。我一般会在重投影前先看一眼原始数据的坐标范围如果单位是 6 位数级别的米数多半是投影坐标系如果是 90 到 105 之间的数多半是经纬度坐标系。这一步可以帮你判断需要定义哪种投影。另一个需要留意的点是互联网地图数据。从在线平台下载的 GeoJSON 往往带偏移即非标准地理坐标直接和测绘坐标系的 shp 叠加会出现几百米的偏移。这个在设计可视化方案时就要提前确认不要等到数据已经接入系统才发现。6.3 字段名和字段类型的限制dbf 格式非常古老字段限制很多字段名最长 10 个字符。超过之后不同软件处理方式不一样有的直接截断有的加序号后缀导致字段名对不上。文本字段最长 254 个字符。如果你的属性里要存一段长描述存到 dbf 会丢失。字段名建议只用英文、数字、下划线。中文字段名在部分转换工具里会出现不可预期的问题尤其通过 ogr2ogr 转其他格式时字段名编码混乱的概率极高。所以写 shp 之前我习惯先做一个数据瘦身只保留后续需要的字段字段名改成英文短名长文本抽出来单独放到外部表关联。这样后续所有转格式都顺畅很多。6.4 大数据量和几何体问题shapefile 单个文件有 2GB 的体积上限这在实际中很少触发但如果数据量极大比如全要素的地形图、高精度道路网还是可能碰到。应对方案是拆分区域或者改用 GeoPackage 等格式。几何体方面shp 不支持复杂拓扑所以面自相交、面重叠、空隙这些问题都无法自动识别和修复。QGIS 提供了一个修复几何Fix geometries工具对自相交要素有较好的处理效果。我在处理一些从 CAD 转过来的 shp 时经常需要先跑一遍修复再做叠加分析。还有一个值得注意的小点有很多 shp 数据带有 M 值和 Z 值通俗说就是每条线/面还附带测量值和高程值。这种数据在某些叠加分析工具里会报不支持 M/Z 值的错解决办法是另存一份时把 M/Z 值去掉或者用工具把几何类型转换一下。老实说shp 这种格式已经存在几十年了技术上确实老态龙钟但它依然是 GIS 数据交换的默认语言。与其抱怨它难用不如把它的脾气摸透。从我个人的经验来说处理大理州这类行政区划 shp 数据最值得养成的一个习惯是拿到任何 shp 的第一时间先看 crs 和 encoding而不是迫不及待地打开地图画图。这两个元数据一旦确定没问题后面所有流程基本就顺了。如果是从同事或第三方手里接过二手数据开口先问一句这个数据的坐标系和编码是什么这句话能帮你省下可能是一整天的排查时间。本文还有配套的精品资源点击获取
返回列表