说明
在C#调用gdal1.9.2时,出现中文乱码,搜索原因说是因为gdal是C++写的,编译成C#时没有考虑不同编码字节长度不同的问题。网上搜了一堆解决方案都失败了。网上大致搜集了一下方案:
-
修改注册编码,CP936/UTF-8/GB2312/GBK等都有
OSGeo.GDAL.Gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "YES"); OSGeo.GDAL.Gdal.SetConfigOption("SHAPE_ENCODING", "");
-
使用gdal类库中的OCR_F_GetFieldAsString方法
IntPtr pNativeData = OGR_F_GetFieldAsString(OSGeo.OGR.Feature.getCPtr(fe), index); string str = Marshal.PtrToStringAnsi(pNativeData);
但是上面两种还是乱码。
解决方案
中文属性乱码
换种思路搜索发现:C++的char*转C# string中文乱码,可能是因为C++返回的char编码是UTF8,Marshal不支持UTF转换,所以必须先转成Unicode再转成UTF8
查看了一下shapefile的编码文件CPG,发现真的是utf-8编码
// 获取string
IntPtr pchar = OGR_F_GetFieldAsString(OSGeo.OGR.Feature.getCPtr(fe), 38);
// 转unicode编码
byte[] bytes = System.Text.Encoding.Unicode.GetBytes(Marshal.PtrToStringUni(pchar));
// 二进制流转字符串
string value = System.Text.Encoding.UTF8.GetString(bytes);
用这个方法取得的值还有点问题,中文都识别出来了,但还是有部分乱码(值正确,但是vs中显示半截乱码),原因还待深入研究。现在暂时用截取的方法规避了一下。
中文字段乱码
在读取shp时,遇到中文字段时,调用getName也会出现乱码的情况。
OSGeo.OGR.FieldDefn pFieldDefn = pFeature.GetFieldDefnRef(0);
pFieldDefn.GetName();
参照上面的解决方案,查到了官网api,试着用相似的方法解决了:
先引入动态库方法,直接使用OGR_Fld_GetNameRef方法
[DllImport("gdal19.dll", EntryPoint = "OGR_Fld_GetNameRef", CallingConvention = CallingConvention.Cdecl)]
public extern static System.IntPtr OGR_Fld_GetNameRef(HandleRef handle);
用OGR_Fld_GetNameRef函数读取字段名,先转为unicode,再转成utf-8
for (int i = 0; i < fieldsCount; i++)
{
// 获取FieldDefn
OSGeo.OGR.FieldDefn pFieldDefn = fe.GetFieldDefnRef(i);
// 解决中文字段乱码,用OGR_Fld函数读取字段名
IntPtr pcharFld = OGR_Fld_GetNameRef(OSGeo.OGR.FieldDefn.getCPtr(pFieldDefn));
// 转为unicode二进制
byte[] bytesFld = System.Text.Encoding.Unicode.GetBytes(Marshal.PtrToStringUni(pcharFld));
// 二进制转为字符串
string valueFld = System.Text.Encoding.UTF8.GetString(bytesFld);
}