4. Shapefile格式详解
把地质钻孔CSV转成Shapefile,很多人以为“导出成功”就结束了,结果在ArcGIS或QGIS里打开发现属性表乱码、中文缺失、坐标飞到海里,或者明明有几百个孔位却只显示一部分。这些问题绝大多数不是软件故障,而是对Shapefile的组成结构和字段约束理解不到位。Shapefile并不是一个单一文件,而是一组同名、同目录、扩展名不同的文件协同工作,缺一不可。本节把它的内部结构拆开讲清楚,为后续的转换与投影校验打好基础。
一、Shapefile是一组文件,不是一个文件
一个可用的Shapefile至少由三个文件构成,通常还会带一个投影文件:
- .shp:主文件,存储几何信息。它按记录顺序保存每个要素的几何类型、坐标串(点、线、面),以及该要素在文件中的位置索引。几何类型在文件头中一次性声明,因此一个Shapefile只能存放一种几何类型(全点、全线或全面),点与面不能混存。
- .shx:索引文件,存储每个要素在.shp中的字节偏移量和记录长度。它让软件能快速定位第N个要素,而不必从头扫描。.shx损坏或与.shp不匹配时,常表现为“能打开但图形错位”或“记录数不对”。
- .dbf:属性表文件,dBASE格式,存储每个要素的属性字段。它与.shp按记录序号一一对应:.shp中第1个几何对应.dbf中第1行属性。这个隐式关联是Shapefile的核心约定,也是转换时最容易出错的地方。
- .prj:投影文件,纯文本,用WKT描述坐标系。它不是必需文件,但缺失时软件无法得知坐标含义,只能当作“未知坐标系”处理,这正是钻孔点位“飞到海里”的常见原因。
此外还可能出现 .sbn/.sbx(空间索引)、.cpg(字符编码说明)、.xml(元数据)等辅助文件。其中.cpg非常关键:它用一行文本声明.dbf的字符编码(如 UTF-8 或 GBK),没有它,中文属性在跨软件打开时极易变成乱码。
二、几何类型与钻孔数据的对应
Shapefile的几何类型在文件头固定,常见有Point、Polyline、Polygon三类。对地质钻孔而言,孔位天然对应Point:每个钻孔一个点,坐标取孔口X、Y(投影坐标)或经度、纬度。如果要把钻孔连成勘探线剖面,则用Polyline;若要表达地层分布或矿体边界,则用Polygon。需要特别提醒:一个Shapefile不能同时存点和面,所以“孔位+地层”必须拆成两个Shapefile,通过属性字段(如地层代号)建立逻辑关联,而不是塞进同一个文件。
点要素的坐标顺序也要注意:Shapefile内部按X、Y存储,X对应东坐标/经度,Y对应北坐标/纬度。若CSV中列名是“纬度、经度”,转换时必须显式指定映射,否则点位会整体旋转90度,表现为“所有孔排成一条竖线”。
三、.dbf字段类型与长度限制
.dbf源自dBASE,字段约束比现代数据库严格得多,转换前必须做字段设计。常用类型包括:
| 类型代号 | 含义 | 典型用途 | 限制 |
|---|---|---|---|
| C | 字符型 | 孔号、岩性名称 | 长度≤254,按字节计 |
| N | 数值型 | 孔深、标高、坐标 | 总宽≤19,含小数点和负号 |
| F | 浮点型 | 品位、含量 | 精度有限,慎用于大数 |
| D | 日期型 | 开孔日期 | 固定8位YYYYMMDD |
| L | 逻辑型 | 是否见矿 | 仅T/F |
两个高频坑:其一,字段名最长10个字符,中文按字节算更紧张,“钻孔编号”这类名字容易被截断成“钻孔编”,转换工具通常静默截断而不报错,导致后续按字段名取值失败;建议统一用英文短名如 HOLE_ID、LITHO、DEPTH。其二,字符型长度按字节而非字符计,UTF-8下一个汉字占3字节,若把“岩性描述”设为长度20,实际只能存6个汉字,超出部分被截掉。设计时应按“最长可能值×字节数”留余量。
N,10,3 表示总宽10位、小数3位,整数部分最多6位。若孔深写成 1234.5678,会被截断或报错。转换前先统计各数值列的最大整数位与小数位,再定宽度。四、属性表与几何的关联机制
.shp与.dbf之间没有显式主键,靠记录序号隐式绑定:第i个几何对应第i行属性。这意味着转换时CSV的行顺序必须与写入几何的顺序严格一致。实践中常见两种破坏方式:一是先按某列排序再写几何、却按原顺序写属性;二是过滤掉坐标为空的行时只删了几何没删属性,造成后续所有记录整体错位一位,表现为“ZK01的坐标配上了ZK02的岩性”。
排查这类问题有一个简单办法:在.dbf中保留一个与几何同源的字段(如孔号),在QGIS中用“按位置选择”或属性表逐行核对前几条记录,看孔号与点位是否吻合。若发现整体错位,可用GDAL的 ogrinfo 查看记录数是否与CSV有效行数一致,再用 ogr2ogr 重新生成索引与属性,而不是手工修补。
五、转换前的字段设计示例
假设钻孔CSV含列:孔号、经度、纬度、孔深、岩性、开孔日期。转换前建议先落一张字段映射表,明确类型、宽度与来源列,避免工具自动推断出错:
目标字段名 类型 宽度/小数 来源CSV列 说明
HOLE_ID C 12 孔号 英文短名,避免截断
LON N 12,6 经度 保留6位小数
LAT N 12,6 纬度
DEPTH N 8,2 孔深 整数最多5位
LITHO C 30 岩性 UTF-8下约10个汉字
OPEN_DATE D 8 开孔日期 转YYYYMMDD
同时生成配套的 .prj(如CGCS2000地理坐标或对应投影带)和 .cpg(写 UTF-8),并在转换后用 ogrinfo -al 检查几何类型、记录数、字段定义与坐标系是否与设计一致。只有这四项都对上,才算真正“转换成功”,而不是仅仅“导出了文件”。