GDAL C#讀取shp中文屬性值亂碼問題


GDAL的C#版本讀取shp中,如果屬性值中含有中文,讀出來有可能是亂碼的問題,根據SWIG生成的C#代碼調試發現問題所在,在Ogr.cs文件中有這么一個函數,代碼如下:

  internal static string Utf8BytesToString(IntPtr pNativeData)
  {
    if (pNativeData == IntPtr.Zero)
        return null;

    int length = Marshal.PtrToStringAnsi(pNativeData).Length; //問題在這句
    byte[] strbuf = new byte[length];
    Marshal.Copy(pNativeData, strbuf, 0, length);
    return System.Text.Encoding.UTF8.GetString(strbuf);
  }

問題就出現在上面這句中,如果shp文件中dbf的編碼是utf-8的時候,pNativeData實際上就是GDAL庫讀取到的一個const char*的地址,這個時候,使用Marshal.PtrToStringAnsi函數返回的長度會變小,下面舉個栗子:
如果GDAL的C++庫返回的const char* pszValue = “中”,那么pNativeData的值實際上就是pszValue這個地址,且用UTF8編碼的時候,pszValue指針對應的內存中的信息應該是”E4 B8 AD 00 XX XX”,后面的XX表示其他的東西,只有前四個有用。
這時pNativeData的值就是上面這個”E4 B8 AD 00 XX XX”字符串的地址,調用下面這句,返回的值居然是2。明明一個3的字符串為啥長度是2,就因為這里長度變短,導致后面轉string的時候丟失了信息,造成了亂碼。

  int length = Marshal.PtrToStringAnsi(pNativeData).Length; //length = 2

本來想試下Marshal.PtrToString其他的函數,結果發現Marshal.PtrToStringAuto和Marshal.PtrToStringUni返回的長度都是16,就更不對了,沒辦法,用了一個笨辦法,寫了個循環來查找長度。修改后的代碼如下:

  internal static string Utf8BytesToString(IntPtr pNativeData)
  {
    if (pNativeData == IntPtr.Zero)
        return null;

    int nMaxLength = Marshal.PtrToStringAuto(pNativeData).Length;
    int length = 0;//循環查找字符串的長度
    for(int i=0; i<nMaxLength; i++)
    {
        byte []strbuf1 = new byte[1];
        Marshal.Copy(pNativeData+i, strbuf1, 0, 1);
        if(strbuf1[0] == 0)
        {
            break;
        }
        length++;
    }

    byte[] strbuf = new byte[length];
    Marshal.Copy(pNativeData, strbuf, 0, length);
    return System.Text.Encoding.UTF8.GetString(strbuf);
  }

同理,將Gdal.cs、Osr.cs這兩個文件里面的這個函數也修改,重新編譯即可解決這個問題。

最后,如果與shp中dbf的編碼使用GBK之類的編碼,請設置SHAPE_ENCODING這個配置項,如果shp文件夾中有同名的cpg文件則可以不用設置,但是確保cpg文件中寫的編碼與dbf中的實際編碼相對應。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM