在C#中使用GDAL创建含中文字段名的Esri Shapefile遇问题求助
问题:GDAL创建Esri Shapefile时中文字段名异常
- 设置编码为
CP936时,创建名为名字的字段报错:Failed to create field name '名字': cannot convert to CP936 - 修改编码为
UTF-8后,ArcGIS Pro中字段名乱码,但要素内容显示正常
原代码
private static void CreateShapeFile(string path, string shapeFileName) { // Register Ogr GdalConfiguration.ConfigureOgr(); // Register Gdal GdalConfiguration.ConfigureGdal(); string pszDriverName = "ESRI Shapefile"; OSGeo.GDAL.Gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "Yes"); //OSGeo.GDAL.Gdal.SetConfigOption("SHAPE_ENCODING", ""); OSGeo.GDAL.Gdal.SetConfigOption("SHAPE_ENCODING", "CP936"); OSGeo.OGR.Driver poDriver = OSGeo.OGR.Ogr.GetDriverByName(pszDriverName); if (poDriver == null) Console.WriteLine("Driver Error"); //Create DataSource OSGeo.OGR.DataSource poDS; poDS = poDriver.CreateDataSource(path + "\\" + shapeFileName + ".shp", null); if (poDS == null) Console.WriteLine("DataSource Creation Error"); //Create Layer OSGeo.OGR.Layer poLayer; string[] options = {"ENCODING=CP936"}; poLayer = poDS.CreateLayer(shapeFileName, null, OSGeo.OGR.wkbGeometryType.wkbPoint, options); if (poLayer == null) Console.WriteLine("Layer Creation Failed"); //Create attribute columns OSGeo.OGR.FieldDefn Field1 = new OSGeo.OGR.FieldDefn("名字", OSGeo.OGR.FieldType.OFTString); Field1.SetWidth(16); OSGeo.OGR.FieldDefn Field2 = new OSGeo.OGR.FieldDefn("Address", OSGeo.OGR.FieldType.OFTString); Field2.SetWidth(80); OSGeo.OGR.FieldDefn Field3 = new OSGeo.OGR.FieldDefn("Lon", OSGeo.OGR.FieldType.OFTString); Field3.SetWidth(20); OSGeo.OGR.FieldDefn Field4 = new OSGeo.OGR.FieldDefn("Lat", OSGeo.OGR.FieldType.OFTString); Field4.SetWidth(20); OSGeo.OGR.FieldDefn Field5 = new OSGeo.OGR.FieldDefn("UID", OSGeo.OGR.FieldType.OFTString); Field5.SetWidth(50); OSGeo.OGR.FieldDefn Field6 = new OSGeo.OGR.FieldDefn("Tag", OSGeo.OGR.FieldType.OFTString); Field5.SetWidth(50); poLayer.CreateField(Field1, 0); poLayer.CreateField(Field2, 1); poLayer.CreateField(Field3, 2); poLayer.CreateField(Field4, 3); poLayer.CreateField(Field5, 4); poLayer.CreateField(Field6, 5); //Create Feature and Point OSGeo.OGR.Feature poFeature = new Feature(poLayer.GetLayerDefn()); OSGeo.OGR.Geometry pt = new Geometry(OSGeo.OGR.wkbGeometryType.wkbPoint); double x = 0; double y = 0; for (int i = 0; i < 50; i++) { poFeature.SetField(0, "你好,GDAL"); poFeature.SetField(1, "TestProperties"); poFeature.SetField(2, "这是一个测试"); poFeature.SetField(3, "TestProperties"); poFeature.SetField(4, "TestProperties"); poFeature.SetField(5, "TestProperties"); y = y + 30; pt.AddPoint(x, y, 0); poFeature.SetGeometry(pt); poLayer.CreateFeature(poFeature); } poFeature.Dispose(); poDS.Dispose(); Console.WriteLine("Mission Completed"); }
解决方案
修正后的代码
private static void CreateShapeFile(string path, string shapeFileName) { // 先设置编码配置,再注册驱动(关键:配置需在驱动初始化前生效) OSGeo.GDAL.Gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "YES"); OSGeo.GDAL.Gdal.SetConfigOption("SHAPE_ENCODING", "GBK"); // 用GBK替代CP936,兼容性更好 // Register Ogr GdalConfiguration.ConfigureOgr(); // Register Gdal GdalConfiguration.ConfigureGdal(); string pszDriverName = "ESRI Shapefile"; OSGeo.OGR.Driver poDriver = OSGeo.OGR.Ogr.GetDriverByName(pszDriverName); if (poDriver == null) { Console.WriteLine("Driver Error"); return; } // 用Path.Combine避免路径拼接错误 string shpPath = System.IO.Path.Combine(path, $"{shapeFileName}.shp"); OSGeo.OGR.DataSource poDS = poDriver.CreateDataSource(shpPath, null); if (poDS == null) { Console.WriteLine("DataSource Creation Error"); return; } // 移除重复的ENCODING配置,全局配置已生效 OSGeo.OGR.Layer poLayer = poDS.CreateLayer(shapeFileName, null, OSGeo.OGR.wkbGeometryType.wkbPoint, null); if (poLayer == null) { Console.WriteLine("Layer Creation Failed"); poDS.Dispose(); return; } //Create attribute columns OSGeo.OGR.FieldDefn Field1 = new OSGeo.OGR.FieldDefn("名字", OSGeo.OGR.FieldType.OFTString); Field1.SetWidth(16); OSGeo.OGR.FieldDefn Field2 = new OSGeo.OGR.FieldDefn("Address", OSGeo.OGR.FieldType.OFTString); Field2.SetWidth(80); OSGeo.OGR.FieldDefn Field3 = new OSGeo.OGR.FieldDefn("Lon", OSGeo.OGR.FieldType.OFTString); Field3.SetWidth(20); OSGeo.OGR.FieldDefn Field4 = new OSGeo.OGR.FieldDefn("Lat", OSGeo.OGR.FieldType.OFTString); Field4.SetWidth(20); OSGeo.OGR.FieldDefn Field5 = new OSGeo.OGR.FieldDefn("UID", OSGeo.OGR.FieldType.OFTString); Field5.SetWidth(50); OSGeo.OGR.FieldDefn Field6 = new OSGeo.OGR.FieldDefn("Tag", OSGeo.OGR.FieldType.OFTString); Field6.SetWidth(50); // 修正原代码的字段赋值错误 // 检查字段创建结果 if (poLayer.CreateField(Field1, 0) != OSGeo.OGR.Ogr.OGRERR_NONE) { Console.WriteLine("创建字段'名字'失败"); } poLayer.CreateField(Field2, 1); poLayer.CreateField(Field3, 2); poLayer.CreateField(Field4, 3); poLayer.CreateField(Field5, 4); poLayer.CreateField(Field6, 5); //Create Feature and Point OSGeo.OGR.Feature poFeature = new OSGeo.OGR.Feature(poLayer.GetLayerDefn()); OSGeo.OGR.Geometry pt = new OSGeo.OGR.Geometry(OSGeo.OGR.wkbGeometryType.wkbPoint); double x = 0; double y = 0; for (int i = 0; i < 50; i++) { poFeature.SetField(0, "你好,GDAL"); poFeature.SetField(1, "TestProperties"); poFeature.SetField(2, "这是一个测试"); poFeature.SetField(3, "TestProperties"); poFeature.SetField(4, "TestProperties"); poFeature.SetField(5, "TestProperties"); y = y + 30; pt.SetPoint(0, x, y, 0); // 用SetPoint更新点,避免累积多个点 poFeature.SetGeometry(pt); if (poLayer.CreateFeature(poFeature) != OSGeo.OGR.Ogr.OGRERR_NONE) { Console.WriteLine($"创建第{i+1}个要素失败"); } } // 释放所有资源 poFeature.Dispose(); pt.Dispose(); poDS.Dispose(); Console.WriteLine("Mission Completed"); }
关键修复点
- 调整配置顺序:必须在注册OGR驱动前设置
SHAPE_ENCODING,否则配置不会被驱动加载。 - 替换编码标识:使用
GBK替代CP936,两者编码范围完全一致,但GDAL对GBK的处理兼容性更好。 - 修正代码bug:原代码中
Field6的宽度设置错误指向Field5,导致字段属性异常;循环中AddPoint会不断向几何对象添加点,改用SetPoint更新单个点。 - 移除重复配置:无需在
CreateLayer时重复指定编码,全局SHAPE_ENCODING配置已覆盖。
额外兼容处理(针对ArcGIS Pro)
如果ArcGIS Pro仍无法正确识别字段名,可手动在Shapefile所在目录创建一个.cpg文件,文件内容仅需一行:GBK。ArcGIS会读取该文件识别编码格式。
内容的提问来源于stack exchange,提问作者MengKe
相关产品推荐
相关产品推荐

