You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在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");
}

关键修复点

  1. 调整配置顺序:必须在注册OGR驱动前设置SHAPE_ENCODING,否则配置不会被驱动加载。
  2. 替换编码标识:使用GBK替代CP936,两者编码范围完全一致,但GDAL对GBK的处理兼容性更好。
  3. 修正代码bug:原代码中Field6的宽度设置错误指向Field5,导致字段属性异常;循环中AddPoint会不断向几何对象添加点,改用SetPoint更新单个点。
  4. 移除重复配置:无需在CreateLayer时重复指定编码,全局SHAPE_ENCODING配置已覆盖。

额外兼容处理(针对ArcGIS Pro)

如果ArcGIS Pro仍无法正确识别字段名,可手动在Shapefile所在目录创建一个.cpg文件,文件内容仅需一行:GBK。ArcGIS会读取该文件识别编码格式。

内容的提问来源于stack exchange,提问作者MengKe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 17:02:07