前面解決了打開mdb亂碼的問題,但又出現讀取中文屬性亂碼的問題,不光是mdb,還有gdb,shp都存在此問題,究其原因依然是封裝C#版時的bug造成的,直接說解決方案:
原版有個Utf8BytesToString方法,直接調用PtrToStringAnsi獲取字節長度,沒有考慮不同編碼字節長度不同的問題。
修改前:
修改后:
internal static string Utf8BytesToString(IntPtr pNativeData) { string result; if (pNativeData == IntPtr.Zero) { result = null; } else { int num = 0; byte[] array = new byte[0]; do { num++; Array.Resize<byte>(ref array, num); Marshal.Copy(pNativeData, array, 0, num); } while (array[num - 1] != 0); if (1 == num) { result = ""; } else { Array.Resize<byte>(ref array, num - 1); result = Encoding.UTF8.GetString(array); } } return result; }
同樣的問題在於SWIGStringHelper類中CreateString方法。
修改前:
修改后:
protected class SWIGStringHelper { [DllImport("ogr_wrap")] public static extern void SWIGRegisterStringCallback_Ogr(OgrPINVOKE.SWIGStringHelper.SWIGStringDelegate stringDelegate); private static string CreateString(IntPtr pNativeData) { string result; if (pNativeData == IntPtr.Zero) { result = null; } else { int num = 0; byte[] array = new byte[0]; do { num++; Array.Resize<byte>(ref array, num); Marshal.Copy(pNativeData, array, 0, num); } while (array[num - 1] != 0); if (1 == num) { result = ""; } else { Array.Resize<byte>(ref array, num - 1); result = Encoding.UTF8.GetString(array); } } return result; } static SWIGStringHelper() { OgrPINVOKE.SWIGStringHelper.SWIGRegisterStringCallback_Ogr(OgrPINVOKE.SWIGStringHelper.stringDelegate); } private static OgrPINVOKE.SWIGStringHelper.SWIGStringDelegate stringDelegate = new OgrPINVOKE.SWIGStringHelper.SWIGStringDelegate(OgrPINVOKE.SWIGStringHelper.CreateString); public delegate string SWIGStringDelegate(IntPtr pNativeData); }
但這樣的修改還是只能處理gdb和shp問題,mdb的還是不行!得調用底層GDAL的API才行。
選來一個擴展方法:
/// <summary> /// 讀取要素字段值 /// </summary> /// <param name="handle"></param> /// <param name="index"></param> /// <returns></returns> [DllImport("gdal204.dll", EntryPoint = "OGR_F_GetFieldAsString", CallingConvention = CallingConvention.Cdecl)] public static extern System.IntPtr OGR_F_GetFieldAsString(HandleRef handle, int index); /// <summary> /// 讀取要素字段值 /// </summary> /// <param name="feature"></param> /// <param name="index"></param> /// <returns></returns> public static string GetFieldAsStringEx(this Feature feature, int index) { IntPtr pStr = OGR_F_GetFieldAsString(Feature.getCPtr(feature), index); return Marshal.PtrToStringAnsi(pStr); } public static string GetFieldAsStringEx(this Feature feature, string name) { var index = feature.GetFieldIndex(name); if (index >= 0) { return (GetFieldAsStringEx(feature, index)); } throw new IndexOutOfRangeException(); }
再使用擴展方法來讀取就好了。
Layer layer = mdbDataSource.GetLayerByIndex(1); FeatureDefn featureDefn = layer.GetLayerDefn(); int iFieldCount = featureDefn.GetFieldCount(); Feature feature = null; while ((feature = layer.GetNextFeature()) != null) { string s = ""; for (int j = 0; j < iFieldCount; j++) { s += feature.GetFieldAsStringEx(j) + "\t\t\t"; } Console.WriteLine(s); }