
干GIS这行数据格式几乎是每天都要碰的东西。借助这篇文章我想把日常工作里最常用的GIS核心数据格式以及数据之间的互相转换这件事从头到尾捋一遍。不仅能帮刚入行的朋友少走弯路也能给做地图开发、数据处理的同行提供一些可直接抄走的经验。我最早接触GIS时从ArcGIS那套shapefile开始后来做空间数据服务又跟GeoJSON、GeoTIFF、GeoPackage这些格式打交道。中间踩过很多坑比如字段名被截断、属性乱码、坐标对不上、交付格式不被对方平台识别等等。时间长了就发现很多问题都不是功能层面的问题而是格式选择和转换处理时埋下的雷。你想把一个.shp转成GeoJSON看起来只是换个后缀但背后牵扯到坐标参考、字段类型、编码、几何结构一个没顾上数据就废了。这篇文章不写高深理论重点讲三件事常见格式是什么、不同场景下怎么选、转换实操和避坑清单。内容以我自己的项目经历为主尽量说人话让你看完之后能直接上手。1. 先把底子打牢GIS核心数据格式有哪些1.1 矢量格式从Shapefile到GeoJSON再到GeoPackage矢量数据用来表达点、线、面是GIS里最常见的结构化空间数据。先说Must老的Shapefile也就是.shp。它是ESRI在90年代提出的格式虽然名字叫一个文件实际至少由三个文件组成.shp存几何、.dbf存属性、.shx存索引。这么老的东西到今天还没被淘汰主要因为几乎所有GIS软件和开发库都认它数据交换成本低。但它槽点很多字段名最多10个字符、文件大小上限2GB、不支持拓扑、几何类型单一、容易漏文件。如果你拿到一个完整的数据包发现只有.shp丢掉了.dbf和.shx那基本就打不开了。再往后是GeoJSON目前Web地图开发里的明星格式。它是基于JSON的几何和属性放在同一个结构里人可读性好前端地图库直接就能解析。Leaflet、OpenLayers、MapLibre这些框架对GeoJSON的支持都很成熟适合做轻量级数据交互。缺点也明显文本文件体积偏大字段类型弱空间索引还得自己做。如果只是几兆数据散布到网页地图上是小事情一旦上百兆网页加载就卡了。KML/KMZ是Google Earth生态里常见的格式也是OGC标准。KML把地理要素、样式、标注信息都写进XML里适合做地图展示、长传放到Google Earth里看。缺点是其设计偏向“可视化”不是分析型数据结构带坐标的多边形叠加快或要素很多时处理效率会比Shapefile和GeoPackage差不少。GPX主要存GPS轨迹和航点户外运动和导航领域用得多属性结构固定简化做GIS分析一般不太用它。还有GMLOGC的XML地理标记语言表达能力很强能描述复杂模型、拓扑、时空数据。但它实在太啰嗦同一份数据用GML写出来体积大概是GeoJSON的两到三倍解析也费劲。实际项目里只有当对方平台强制要求GML交换格式时我才会掏出来用平时真的很少碰。重点说下GeoPackage。这是后起之秀基于SQLite数据库单文件搞定把矢量、栅格、属性、样式都装进一个.container里不同于传统“一堆文件”的散装习惯。它支持空间索引、有较强的字段类型、没有Shapefile那样的名称和体积限制还能同时容纳多个图层。我和不少同行这两年都倾向用GeoPackage做项目归档和交付尤其是复杂的多图层项目比Shapefile舒服太多。1.2 栅格格式从GeoTIFF到Cloud Optimized GeoTIFF栅格数据说白了就是像元阵列遥感影像、高程模型、气温插值图都是栅格。GIS里最核心的栅格格式当属GeoTIFF。它是TIFF加上地理参考信息把像元坐标和投影信息写进文件头几乎所有遥感处理软件都认。实际交付遥感影像时如果对方没特殊要求我一般首选GeoTIFF。如果你的整套流程在云计算或对象存储上跑那更要认识Cloud Optimized GeoTIFF简称COG。COG本质还是GeoTIFF只是把数据组织成金字塔块状结构配合HTTP Range请求访问巨大影像时不用下载整个文件只读取需要出图的部分。这几年COG已经成了互联网GIS影像服务的事实标准。除了GeoTIFF还有一些遗留格式如IMAGINE的.img、ERDAS的.e00、MrSID不同软件生态遗留的不同遇到旧项目迁移时才处理。还有MBTiles基于SQLite的瓦片包适合离线地图或者移动端展示可以理解成把瓦片装进一个“盒子”。另外气象海洋科研里常见的NetCDF/HDF能存多维时空数据比如海温、气压场跟普通栅格不是一回事转换时不能套用影像逻辑得用专门工具。1.3 挡在很多新手前面的两个底层因素坐标系与字段类型谈到格式就不能跳过坐标系。坐标系本质上决定了你那一串坐标数值“到底代表地球上的哪个位置”。GIS里最常见的两类坐标系地理坐标系如WGS84、CGCS2000用经纬度表达和投影坐标系如Web Mercator用平面坐标表达。不同坐标系之间数值差得非常明显。比如WGS84的经纬度和Web Mercator的平面坐标差了好几个数量级。转换数据时如果坐标参考信息丢失或者坐标系标错后续所有空间分析都会偏离“十万八千里”。这点也是很多人“转完格式后图糊了”的第一大原因。字段类型看似和数据格式没什么关系实际影响很大。矢量数据的属性表里有文本、整型、浮点型、日期型、布尔型等区分。不同格式支持的字段类型并不完全一样比如ESRI Shapefile的dbf属性表只有字符型、数值型、日期型等有限类型而GeoJSON更倾向把数字和字符串都按JSON类型来处理。从GeoPackage转到Shapefile时日期时间字段经常被截成日期或字符串浮点精度也会受影响。转换前摸清字段类型比转换时临时补救要省事得多。2. 不是工具不行是场景没想清楚格式选型逻辑2.1 交付给什么环境决定选什么格式在实际项目里谈“哪种格式最好”没有意义关键是“数据准备交给谁”。我一般先问三个问题对方用什么平台打开、数据要存多久、是否有硬件和网络限制。如果对方用的是老版本的桌面GIS或者是一个兼容性很保守的三方平台我大概率还是输出Shapefile。虽然它有各种限制但大家都认识它不会出现“拿到文件打不开”的尴尬。相反如果数据是给自己团队做新项目用尤其一套数据里面可能有好几十个图层我就直接用GeoPackage一个文件管所有字段名长度也放得开还自带空间索引性能明显更快。就我处理过的项目看80%的“格式不合适”都是前期没问清楚导致的。曾经有一次我跟对方口头确认为GeoJSON结果对方项目组实际用的桌面GIS版本只支持Shapefile我交付过去的GeoJSON打开时一片空白最后返工重转。2.2 Web开发和项目归档是选轻量还是选厚重面向Web地图的时候GeoJSON因为轻量、直接解析特别适合把属性挂在地图要素上做交互。但要注意数据量一大GeoJSON反而成了负担。一次我拿全国河流线数据做Web可视化原始数据有近200万条几何直接转GeoJSON导出后文件有1.5GB浏览器根本加载不动。后来改成将数据切割成按屏幕可见范围加载的矢量瓦片体验立刻好起来。如果你在Web端用几十MB级别可以Local GeoJSON再大就用GeoPackage或矢量切片如PMTiles、MBTiles来兜底。如果是项目归档建议别用散装的Shapefile。散装文件一来容易漏二来以后交接不方便。用GeoPackage封装成单文件连样式都能一起存进去归档和交付都很干净。前提是对方没有强制指定格式。2.3 空间数据库怎么参与格式转换很多人做数据库层面和文件层次之间的转换时容易懵。比如PostGIS数据库里有一批表要给出去是导成Shapefile还是GeoJSON我的经验是先看用途对方要临时浏览就用GeoJSON或GeoPackage对方要进自己的数据库最好导出为SQL转储或直接提供GeoPackage再入库。数据库到文件之间转换除了能导出全部字段还能只导出当前视图或查询结果这在实际业务里非常有用。反过来从文件格式导入PostGIS时我最常用的做法是先用ogr2ogr把Shapefile或GeoJSON导成PostgreSQL可识别的数据或者直接建一个空表把属性结构提前建好再用入库工具灌进去。这样字段类型比较可控不会出现自动建表后类型不匹配的问题。3. 实操环节转换前的准备和一条常用转换路线3.1 转换前做的数据“体检”转换不是说拿起鼠标“另存为”就行。我建议每个转换前花两分钟做个数据体检先看有没有有效的坐标参考信息。打开属性找到坐标系如果显示未知必须先补上正确的坐标系否则后续转换都是白搭。再看字段名和字段类型。有没有超过10个字符的字段名有没有中文名有没有日期时间、双精度这些特殊类型。抽几处几何看是否合法。常见问题包括明明应该全是多边形但里面混着多点有空几何有自相交有重复顶点。最后确认数据完整性和编码。看属性表里的中文是正常显示还是乱码有没有缺失值。这些检查用桌面GIS打开看一眼就行或者命令行里用ogrinfo很快。反正一两分钟的事比转完再排查省时间得多。3.2 GDAL/OGR命令行批量转换的不二选择GDAL/OGR是GIS格式转换的“瑞士军刀”几乎所有的GIS工具都在底层用它。桌面GIS“另存为”能做的事它都能做而且能批量、能写脚本、能精确控制参数。我日常最频繁用的是ogr2ogr专门转换矢量数据。推荐在Windows下装OSGeo4W或者直接用QGIS内置的OSGeo4W ShellLinux/macOS环境可以用apt或conda安装gdal。先给一个最朴素、最常用的转换命令# 将shapefile转成GeoJSON同时把坐标系统一为WGS84经纬度 ogr2ogr -f GeoJSON output.geojson input.shp -t_srs EPSG:4326这个命令相当常用。不加-t_srs默认保留源数据坐标系加了-t_srs就会对坐标做数学变换。绝大多数Web应用都默认要WGS84经纬度所以输出GeoJSON时我都会顺手加上它。如果是三维、带高程的矢量转换时默认可能丢失Z值需要加上# 保留Z值适合带高程的点、线、面 ogr2ogr -f GeoJSON output_3d.geojson input.shp -t_srs EPSG:4326 -z再从GeoJSON转回Shapefile时字段名超过10个字符的会自动截断容易引起字段对应问题。这时最好先对字段名做规范化处理。用ogr2ogr也可以指定输出字段的子集# 只导出需要的字段列 ogr2ogr -f ESRI Shapefile output.shp input.geojson -select id,name,area批量处理多个文件时写个循环即可。比如把当前目录下所有.shp转成GeoJSON# 批量转换shp为geojson for i in *.shp; do ogr2ogr -f GeoJSON ${i%.shp}.geojson $i -t_srs EPSG:4326 done栅格数据则用gdal_translate做格式转换和重采样用gdalwarp做坐标重投影。下面几个命令很常用# 把一个非标准影像格式转成GeoTIFF gdal_translate -of GTiff input.img output.tif # 把GeoTIFF重投影到WGS84 gdalwarp -t_srs EPSG:4326 input.tif output_4326.tif # 转成Cloud Optimized GeoTIFF gdal_translate input.tif output_cog.tif -of COG -co COMPRESSDEFLATE # 给巨大栅格建立金字塔便于快速浏览 gdaladdo -r average input.tif 2 4 8 16 32这里特别提醒gdal_translate是“转格式”不负责“转坐标系”。gdalwarp才会对像元值做重采样和重投影。不少人拿着gdal_translate想把WGS84的影像转成Web Mercator折腾半天发现坐标没变就是这个原因。3.3 如果不想写命令行QGIS另存为五步法不是所有场景都必须上命令行。同事或者甲方给的数据量不大我经常直接用QGIS。操作流程就五步在图层列表里找到要转换的图层右键选择“导出”里的“另存为”。在对话框里选格式比如GeoJSON、GeoPackage、Esri Shapefile。设置文件名和保存路径。最关键的一步设置目标坐标参考系统CRS。如果希望转成WGS84经纬度就选EPSG:4326如果希望保留原坐标系就选“图层CRS”。勾选“将所选要素保存到新文件”如果只要筛选后的子集就提前选中或按属性筛选。QGIS“另存为”本质上也是调用底层GDAL库但界面友好适合一次性的、非批量的处理。如果你的原始数据是File Geodatabase里的多个图层想统一转成GeoPackage可以直接把GDB拖进QGIS再逐个导出也可以把GDB作为一个整体导出到GeoPackage。这里有个技巧QGIS里可以把多个图层拖进同一个GeoPackage图层名手动设置这样交付给别人的就是单个结构清晰的数据库文件。4. 常见格式转换问题与排查笔记4.1 转换后字段名被截断、重名这是把数据从GeoPackage、GeoJSON往Shapefile转时最典型的坑。Shapefile的dbf属性表字段名最多10个字符而且只支持字母、数字、下划线不支持中文字段名和部分特殊符号。一旦源字段是“population_density”转成Shapefile后就成了“populati_d”这类残缺名。遇到这个问题我有两个习惯一是能不用Shapefile交付就不用它改用GeoPackage二是不得不转时先检查字段名规范性把超长的字段名改短并把中文名改成拼音或英文。不要等转完再修补过程很痛苦。4.2 中文属性值乱码中文乱码通常出在Shapefile上。Shapefile的.dbf文件存储属性时编码可能是GBK或UTF-8而不同的应用程序读取时默认编码不一样。比如在QGIS里直接读一个GBK编码的Shapefile却没有指定编码中文很容易变问号。我的排查方法是观察数据目录里有没有.cpg文件它记录了字符编码如果文件不存在就先在QGIS的图层属性里尝试切换“数据源编码”把GBK改成UTF-8看哪个能正常显示。从命令行读取时可以显式告诉GDAL# 读取shapefile时指定编码为GBK再转成UTF-8的GeoJSON ogr2ogr -f GeoJSON output.geojson input.shp --config SHAPE_ENCODINGGBK -lco ENCODINGUTF-8转换后记得检查属性表确认中文没有变成乱码。特别是做大数据批处理时更要抽样看几个属性值。4.3 坐标系只换标签没换坐标这个问题重复出现太多次了。区别两个字一个是“分配坐标系”一个是“重投影”。在QGIS里如果只修改图层的CRS设置比如把原本WGS84坐标改标成Web Mercator那么坐标数值不变只是给数据“贴了个假标签”地图上会乱。真正要变换必须在导出时选择目标CRS或者用gdalwarp做重投影。命令行里一字之差效果天差地别# -a_srs 表示“强制声明坐标系统”不改变坐标值 gdal_translate -a_srs EPSG:4326 input.tif output_wgs84.tif # -t_srs 表示“变换坐标系统”会重采样像元 gdalwarp -t_srs EPSG:4326 input.tif output_wgs84.tif矢量也一样ogr2ogr里用-t_srs会触发重投影-a_srs只是改变描述。很多人在做Web地图时把数据坐标从Web Mercator“改标”成WGS84结果地图位置偏到天边去就是没搞懂这两者的区别。4.4 几何类型不一致和空几何导致转换失败有些数据集表面看起来全是面实际混着线或点有些还包含空几何。转换时如果目标格式或图层对几何类型有严格限制就可能导致要素丢失或直接报错。我建议转换前后分别统计几何类型用QGIS或ogr2ogr都能做。转换过程中遇到个别坏要素可以跳过不中断# 跳过转换失败的要素尽量保证整体流程跑完 ogr2ogr -f GeoJSON output.geojson input.shp -skipfailures但-skipfailures只是治标若有大量失败要素还是要回到源数据做清洗。比如把所有几何统一成MultiPolygon、删除空几何、修复自相交多边形再做转换。用QGIS的“修复几何”工具或者PostGIS的ST_MakeValid也可以。4.5 大数据量转换内存和性能怎么优化大数据量转换最怕的就是内存耗尽或长时间假死。GDAL本身是流式处理的不会把全部数据一股脑加载到内存但有些设置会让人措手不及。比如重投影栅格数据用gdalwarp时默认可能开很多线程i/o和内存都拉满。我碰到过一个几十GB影像的情况系统直接卡死。后来改成限制内存和线程数# 限制缓存为1GB线程数4避免卡死 gdalwarp -t_srs EPSG:3857 -wm 1024 -multi input.tif output_3857.tif矢量大数据量转换通常瓶颈在属性编码和几何处理上。先把目标格式定为GeoPackage给几何字段建空间索引导入效率比Shapefile高不少。还有一种做法是分块处理把源数据按空间范围切割逐块转换后再合并。4.6 KML和KMZ的特殊限制KML是把“要素样式视角”都写在XML里的格式给Google Earth用很方便但转换时容易吃亏。它不支持复杂的数据类型属性字段类型都偏弱GeoTIFF这种栅格数据也直接放不进去。把Shapefile转KML时我习惯先确认坐标系是WGS84因为KML默认要求WGS84经纬度如果源数据是投影坐标必须先用-t_srs EPSG:4326做重投影。样式方面KML支持图标、线宽、颜色但从一般GIS样式转过去时符号经常对不上需要在Google Earth里重新调。饬这玩意儿时我想起一句话KML更像个“演示格式”别指望它能承载复杂的数据模型。5. 我自己解决格式转换问题的一套思路5.1 一页纸就能写清楚的决策清单处理数据多了我养成了一个习惯任何格式转换前先在脑中过一遍决策清单。目标平台能不能直接读这个格式不能的话优先转换为它支持的格式。数据量多大小于50MB的矢量转GeoJSON大的转GeoPackage或矢量瓦片。坐标系有没有明确要求地图服务通常用WGS84国内一些系统用CGCS2000底图展示可能用Web Mercator。字段要不要保留中文名字段名长度是否超限转换成Shapefile前先处理。属性里有日期、时间、浮点精度敏感字段吗换格式前确认类型是否会被压缩。有没有自定义样式、注记、标注需要保留这类信息很容易在转换中丢失必须额外导出或单独说明。是否需要批量、定时转换要的话就上GDAL脚本别在界面里手动点。这套清单不是死的但能省下大量返工时间。我对团队里的新人也是这么要求的你可以不会写脚本但不能不懂格式和坐标系。5.2 把“转换”当数据治理的最小模块来管理很多人觉得转换是顺手一做的事但我更愿意把它当成数据治理的一部分。数据格式只是承载方式真正值钱的是坐标、属性、关系和语义。每一次转换都应该尽量保住原有信息不丢失、坐标无误差、字段不乱截、编码不乱换。我处理交付数据时都会额外生成一个数据说明文件把坐标系、字段含义、属性编码、转换工具和参数记清楚。看起来多花了十分钟但后续对接的人和调查方都能省下大量的沟通成本。这背后我倾向于尽量统一使用GeoPackage和GeoTIFF作为内部生产格式既避免Shapefile的字段限制又不像GeoJSON那样在数据库量一大会有性能瓶颈。只有在真正需要外部系统或特定平台时才面向目标环境做导出转换。这样“先沉淀再输出”的做法长期来看容错率高很多。最后再分享一个我养成的习惯转换后永远不要只看“有没有成功”还要打开结果做一次视觉抽检至少叠加一个底图确认图层位置、属性值和坐标系都正常。尤其在有条件的时候用多个工具交叉验证一遍。格式转换看似简单实际是“生产环境里比较容易出事故的一环”。把这层功夫做到位后面做分析、出图、开发才会顺畅。