经纬志
首页 / 实战手册 / 数据加载

Shapefile 属性表中文全是乱码,几何却完全正常

先看结论

边界线画得一丝不差,属性弹窗里的地名却是「鍖椾含甯傚湴鍥炬」。

最后验证 2026-11-03 · 多技术栈 · 更新 2026-10-29 · 引用本文

现象

打开 districts.shp,几何位置正确, 属性表里的 NAME 字段显示为 鍖椾含甯傚湴鍥炬, 另一份文件显示为 ?????。 ogr2ogr 转换时控制台报 Warning 1: One or several characters couldn't be converted correctly from UTF-8 to ISO-8859-1。

原因

Shapefile 的 .dbf 本身不记录编码。GDAL 判断顺序是: 先看有没有 .cpg 文件,再看 .prj 里的 ENCODING, 最后退回系统默认代码页。

鍖椾含 是典型的 UTF-8 字节被按 GBK 解读的结果: 「北京」的 UTF-8 是 E5 8C 97 E4 BA AC, 每两字节按 GBK 解码就成了三个生僻汉字。 反过来,GBK 字节被按 UTF-8 解码则会出现 ????? 或替换符。

实际编码被按什么读典型表现
UTF-8GBK鍖椾含甯傚湴鍥炬(生僻字成串)
GBKUTF-8问号、方块或替换符
GBKLatin-1中 这种双字节乱码

排查过程

  1. 检查 shapfile 同目录下有没有 .cpg 文件,内容应为 UTF-8 或 GBK。
  2. 用十六进制看一个已知汉字的字节。三个字节且首字节 E4~E9 是 UTF-8,两个字节且首字节 B0~F7 是 GBK。
  3. 用 ogrinfo -al 输出几个字段值,确认乱码规律。
  4. 用检测工具对 .dbf 跑一次编码猜测,不要靠肉眼看。
# 查看 dbf 编码声明
ogrinfo -al -so districts.shp | Select-String -Pattern "Encoding"

# 用 chardet 检测
python -c "import chardet;print(chardet.detect(open('districts.dbf','rb').read(20000)))"
# {'encoding': 'GB2312', 'confidence': 0.99}

解决方案

补一个 .cpg 文件是最省事的做法,不改动数据本身。 需要统一到 UTF-8 时用 ogr2ogr 重写。

# 方案一:写 .cpg 声明实际编码(GBK)
Set-Content -Path districts.cpg -Value "GBK" -Encoding ASCII

# 方案二:整体转成 UTF-8,同时生成 .cpg
ogr2ogr -f "ESRI Shapefile" out districts.shp -lco ENCODING=UTF-8

# 方案三:GeoJSON 输出时指定源编码
ogr2ogr -f GeoJSON districts.geojson districts.shp -lco ENCODING=GBK

前端用 shapefile.js 解析时,直接传 encoding 参数, 不要依赖库的自动推断。

const source = await shp('/data/districts.shp');
const dbffile = await dbf('/data/districts.dbf', { encoding: 'gbk' });
const geojson = new GeoJSON(source, { dbffile });

验证

属性表中的 NAME 应显示为「北京市」,长度与原始记录一致; 随机抽 20 条,全部可读,无问号与替换符。

SELECT NAME, length(NAME) FROM districts LIMIT 5;
-- 北京市 | 3
-- 天津市 | 3

# 命令行快速核对
ogrinfo -al districts.shp | Select-String "NAME" | Select-Object -First 3

适用版本

工具 / 库版本说明
GDAL / ogr2ogr3.6 及以上优先读 .cpg,其次读系统代码页
QGIS3.28 及以上图层属性里可手动指定编码
shapefile.js6.xDBF 需显式传 encoding
ArcGIS Pro3.x默认按 UTF-8 写,旧数据需登记代码页
引用本文

经纬志(2026)。《Shapefile 属性表中文全是乱码,几何却完全正常》。https://www.jingweizhi.com/cookbook/shp-gbk-garbled.html(访问日期 2026-11-03)。