gdal在处理SHP文件的时候总会遇到中文字段和中文属性值的乱码问题、获取postgresql中的中文表名的时候、mdb中的中文表名,造成这些的原因一些是由于编码问题,还有是gdal上层封装的bug,在公司大佬的提点下获取到了解决方案,掉用c api,那么首先得找到API的名称:
https://gdal.org/python/index.html
先设置环境变量
OSGeo.GDAL.Gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");
OSGeo.GDAL.Gdal.SetConfigOption("SHAPE_ENCODING", "");
然后写扩展方法
public static class GetRightString
{
[DllImport("gdal300.dll", EntryPoint = "OGR_F_GetFieldAsString", CallingConvention = CallingConvention.Cdecl)]
public extern static System.IntPtr OGR_F_GetFieldAsString(HandleRef handle, int i);
[DllImport("gdal300.dll", EntryPoint = "OGR_F_GetFieldAsBinary", CallingConvention = CallingConvention.Cdecl)]
public extern static System.IntPtr OGR_F_GetFieldAsBinary(HandleRef handle, int index, out int byteCount);
[DllImport("gdal300.dll", EntryPoint = "CPLStrnlen", CallingConvention = CallingConvention.Cdecl)]
public extern static uint CPLStrnlen(IntPtr handle, uint nMaxLen);
public static String getRightStr(Feature fe, int index, string workspaceType)
{
if (workspaceType == "GDB")
{
int byteCount = 0;
IntPtr pIntPtr = OGR_F_GetFieldAsBinary(OSGeo.OGR.Feature.getCPtr(fe), index, out byteCount);
byte[] byteArray = new byte[byteCount];
Marshal.Copy(pIntPtr, byteArray, 0, byteCount);
//Console.WriteLine(byteCount);
string str = System.Text.Encoding.UTF8.GetString(byteArray);
return str;
}
else if (workspaceType == "SHP")
{
IntPtr pchar = OGR_F_GetFieldAsString(OSGeo.OGR.Feature.getCPtr(fe), index);
int length = (int)CPLStrnlen(pchar, uint.MaxValue);
byte[] strbuf = new byte[length];
Marshal.Copy(pchar, strbuf, 0, length);
string utf8String = System.Text.Encoding.UTF8.GetString(strbuf);
return utf8String;
}
else
{
return fe.GetFieldAsString(index);
}
}
[DllImport("gdal300.dll", EntryPoint = "OGR_F_SetFieldString", CallingConvention = CallingConvention.Cdecl)]
public extern static void OGR_F_SetFieldString(HandleRef handle, int index, string val);
public static void setFieldString(Feature fe, int index, string val, string workspaceType)
{
if (workspaceType == "SHP")
{
OGR_F_SetFieldString(OSGeo.OGR.Feature.getCPtr(fe), index, val);
}
else
{
fe.SetField(index, val);
}
}
[DllImport("gdal300.dll", EntryPoint = "OGR_Fld_GetNameRef", CallingConvention = CallingConvention.Cdecl)]
public extern static System.IntPtr OGR_Fld_GetNameRef(HandleRef handle);
[DllImport("gdal300.dll", EntryPoint = "OGR_DS_GetLayer", CallingConvention = CallingConvention.Cdecl)]
public extern static System.IntPtr OGR_DS_GetLayer(IntPtr handle, int nIdx);
[DllImport("gdal300.dll", EntryPoint = "OGR_L_GetName", CallingConvention = CallingConvention.Cdecl)]
public extern static System.IntPtr OGR_L_GetName(HandleRef handle);
public static string GetFieldNameEx(FieldDefn layer)
{
IntPtr pName = OGR_Fld_GetNameRef(OSGeo.OGR.FieldDefn.getCPtr(layer));
int length = (int)CPLStrnlen(pName, uint.MaxValue);
byte[] strbuf = new byte[length];
Marshal.Copy(pName, strbuf, 0, length);
string utf8String = System.Text.Encoding.UTF8.GetString(strbuf);
return utf8String;
}
public static string GetNameEx(Layer layer)
{
IntPtr pName = OGR_L_GetName(OSGeo.OGR.Layer.getCPtr(layer));
int length = (int)CPLStrnlen(pName, uint.MaxValue);
byte[] strbuf = new byte[length];
Marshal.Copy(pName, strbuf, 0, length);
string utf8String = System.Text.Encoding.UTF8.GetString(strbuf);
return utf8String;
}
}
调用方法:
shp创建中文字段乱码:
FeatureDefn pgDef = lyPG.GetLayerDefn();
int iFieldCount = pgDef.GetFieldCount();
FieldDefn pgFieldDef = null;
FieldDefn shpFdefn = null;
List<string> lstField = new List<string>();
string fieldName = "";
for (int j = 0; j < iFieldCount; j++)
{
pgFieldDef = pgDef.GetFieldDefn(j);
fieldName = pgFieldDef.GetName();
fieldName = GetRightString.GetFieldNameEx(pgFieldDef);
shpFdefn = new FieldDefn(fieldName, pgFieldDef.GetFieldType());
shpFdefn.SetName(fieldName);
lstField.Add("\"" + fieldName.ToUpper() + "\"");
shpFdefn.SetWidth(pgFieldDef.GetWidth());
shpFdefn.SetPrecision(pgFieldDef.GetPrecision());
lySHP.CreateField(shpFdefn, 1);
}
获取图层名乱码问题:
lyPG = pgDataSource.GetLayerByIndex(l);
layerName = MyDataConvertTool.DataConvertUtils.GetRightString.GetNameEx(lyPG);
获取中文字段值:
sVal = GetRightString.getRightStr(fromFeature, cgFieldIndex, "SHP");
shp属性赋值乱码问题:
GetRightString.setFieldString(toFeature, tagFieldIndex, sVal, "SHP");
参考: