最省事的方式是使用 NetTopologySuite.IO.ShapeFile 库,它纯托管、无本地依赖,自动关联 .shp/.shx/.dbf,但需确保三文件同目录且编码匹配(优先读 .cpg),缺一或编码错将导致解析失败或乱码。

用 NetTopologySuite 读取 .shp 文件最省事
ESRI Shapefile 是复合文件(.shp + .shx + .dbf),C# 原生不支持,得靠第三方库。目前最轻量、无本地依赖、NuGet 可直接装的是 NetTopologySuite.IO.ShapeFile —— 它不调 GDAL,也不 require ArcGIS Runtime,纯 .NET Standard 2.0。
常见错误是只传 .shp 路径却忽略同目录下必须存在的 .shx 和 .dbf:缺任一都会抛 System.IO.FileNotFoundException 或解析出空几何。
- 安装:
dotnet add package NetTopologySuite.IO.ShapeFile - 读取时路径必须指向
.shp文件,但库会自动找同名.shx和.dbf,别手动拆开处理 - 坐标系默认按
.prj解析;没.prj时返回null,不是 WGS84 —— 别默认当成经纬度用 - 字段类型映射较简单:
DBF的C→string,N→double?,整数可能带小数位,注意Convert.ToInt32()前判空
ShapefileDataReader 不能直接 new,得用 ShapefileDataWriter 写入时小心字段长度
ShapefileDataReader 没公开构造函数,必须通过 ShapefileDataWriter 的静态方法创建;反过来,写入时如果 .dbf 字段定义长度不够,写字符串超长会静默截断,不报错但数据丢了。
- 读取示例:
using var reader = ShapefileDataReader.Read("data.shp"); - 写入前必须先定义
DbfColumn:比如new DbfColumn("NAME", 'C', 50, 0),第二个参数是 DBF 类型码,'C'是字符串,50是最大字符数 —— 超过就丢字 - 几何类型必须和
.shp文件头一致:点写成ShapeType.Point,面必须用ShapeType.Polygon,混用会导致 ArcGIS 打不开 - 写入后不会自动生成
.prj,要手动写一个 WKT 字符串到同名.prj文件里,否则 QGIS 加载时坐标偏移
中文字段名或属性值乱码?检查 .cpg 文件和编码参数
Shapefile 的 .dbf 本身不存编码信息,传统用 GBK(国内软件如 MapGIS),新标准倾向 UTF-8。但 NetTopologySuite 默认按 Encoding.Default(Windows 简体中文是 GBK)读,如果 .dbf 实际是 UTF-8 就全乱码。
- 优先看有没有
.cpg文件:有就按它写的编码(如内容是UTF-8);没有则按系统默认 - 强制指定编码:用
ShapefileDataReader.Read(path, encoding: Encoding.UTF8) - 写入时无法指定
.dbf编码,NetTopologySuite固定用Encoding.Default,所以中文入库前确保环境是 GBK,或改用GDAL.NET(需本地 dll) - 字段名乱码更隐蔽:
.dbf头部字段名只支持 10 字节,中文占 2–3 字节,最多存 3–4 个汉字,超长会被截断且不警告
想用 GDAL.NET?注意它不是纯托管,部署要配 dll
如果项目已用 GDAL(比如要做投影转换、栅格叠加),GDAL.NET 功能全,但它是 C++ 封装,nuget 包里带不同平台的 gdal.dll,发布时必须把对应平台的 runtimes 目录一起拷过去,否则运行时报 DllNotFoundException。
- 安装:
dotnet add package GDAL.NET(选带 runtime 的版本,如GDAL.NET.Windows) - 首次调用前必须
OSGeo.GDAL.Gdal.AllRegister(),否则Open()返回 null - 读
.shp用Ogr.Open(),不是Gdal.Open()—— 后者只开栅格 - 字段值获取用
feature.GetFieldAsString("name"),别用.GetFieldAsInteger直接转,空值会崩
真正麻烦的不是读写本身,是 .prj 和 .cpg 这两个不起眼的小文件——少一个,坐标就飞;错一个编码,中文就糊。它们不显眼,但决定你导出的数据别人能不能打开。










