GDAL寫入FileGDB中文屬性亂碼問題
阿新 • • 發佈:2018-12-29
GDAL庫中提供了兩個驅動來訪問FileGDB格式,一個是基於ESRI提供的FileGDBAPI庫來訪問gdb,支援讀寫,另外一個是gdal自己寫的OpenFileGDB驅動來訪問,只支援讀,不支援寫。
本文主要是針對ESRI提供的FileGDBAAPI庫的驅動來說。只用FileGDB驅動建立gdb時,再寫入中文屬性值時,會出現亂碼,下面給出解決方案。
在FileGDB的資料夾中,有個FGdbUtils.cpp的問題,其中定義了兩個函式,原型如下:
這兩個函式的目的就是寬位元組和窄位元組相互轉換。但是在轉換過程中對於編碼指定的問題導致轉換結果不對,從而導致寫入gdb檔案中的中文屬性值亂碼。std::wstring StringToWString(const std::string& s); std::string WStringToString(const std::wstring& s);
下面是gdal庫中對於上述兩個函式的實現:
/*************************************************************************/ /* StringToWString() */ /*************************************************************************/ std::wstring StringToWString(const std::string& utf8string) { wchar_t* pszUTF16 = CPLRecodeToWChar( utf8string.c_str(), CPL_ENC_UTF8, CPL_ENC_UCS2); std::wstring utf16string = pszUTF16; CPLFree(pszUTF16); return utf16string; } /*************************************************************************/ /* WStringToString() */ /*************************************************************************/ std::string WStringToString(const std::wstring& utf16string) { char* pszUTF8 = CPLRecodeFromWChar( utf16string.c_str(), CPL_ENC_UCS2, CPL_ENC_UTF8 ); std::string utf8string = pszUTF8; CPLFree(pszUTF8); return utf8string; }
從上述程式碼中可以看出,GDAL庫中將所有的字串全部預設為UTF-8的編碼,然後直接進行了轉換,如果使用中文,且沒有使用UTF-8對中文進行編碼,那麼再使用上述兩個函式進行轉換時,肯定會出現亂碼問題,針對這個問題,修改上面的程式碼中,添加了一個配置項,類似shp檔案的SHP_ENCODING配置項用於指定輸入的字元編碼,此處配置項名稱改為FILEGDB_ENCODING,將上述兩個函式修改為如下:
修改完儲存,重新編譯GDAL,如果使用的外掛,直接編譯File GDB的外掛dll,將生成的ogr_filegdb.dll放到gdal的外掛目錄即可。/*************************************************************************/ /* StringToWString() */ /*************************************************************************/ std::wstring StringToWString(const std::string& utf8string) { const char* pszFileGDBEncoding = CPLGetConfigOption("FILEGDB_ENCODING", CPL_ENC_UTF8); char* pszUTF8String = NULL; if (EQUAL(pszFileGDBEncoding, CPL_ENC_UTF8)) pszUTF8String = CPLStrdup(utf8string.c_str()); else pszUTF8String = CPLRecode(utf8string.c_str(), pszFileGDBEncoding, CPL_ENC_UTF8); wchar_t* pszUTF16 = CPLRecodeToWChar( pszUTF8String, CPL_ENC_UTF8, CPL_ENC_UCS2); std::wstring utf16string = pszUTF16; CPLFree(pszUTF16); CPLFree(pszUTF8String); return utf16string; } /*************************************************************************/ /* WStringToString() */ /*************************************************************************/ std::string WStringToString(const std::wstring& utf16string) { char* pszUTF8 = CPLRecodeFromWChar( utf16string.c_str(), CPL_ENC_UCS2, CPL_ENC_UTF8 ); std::string utf8string = pszUTF8; CPLFree(pszUTF8); const char* pszFileGDBEncoding = CPLGetConfigOption("FILEGDB_ENCODING", CPL_ENC_UTF8); if (EQUAL(pszFileGDBEncoding, CPL_ENC_UTF8)) return utf8string; else { char* pszLocalString = CPLRecode(utf8string.c_str(), CPL_ENC_UTF8, pszFileGDBEncoding); utf8string = pszLocalString; CPLFree(pszLocalString); return utf8string; } return utf8string; }
在使用的時候,設定配置項FILEGDB_ENCODING=CP936(GBK)等即可。
命令列使用:--config FILEGDB_ENCODING CP936
程式碼中使用:CPLSetConfigOption("FILEGDB_ENCODING", "CP936")