GDAL庫中提供了兩個驅動來訪問FileGDB格式,一個是基於ESRI提供的FileGDBAPI庫來訪問gdb,支持讀寫,另外一個是gdal自己寫的OpenFileGDB驅動來訪問,只支持讀,不支持寫。
本文主要是針對ESRI提供的FileGDBAAPI庫的驅動來說。只用FileGDB驅動創建gdb時,再寫入中文屬性值時,會出現亂碼,下面給出解決方案。
在FileGDB的文件夾中,有個FGdbUtils.cpp的問題,其中定義了兩個函數,原型如下:
std::wstring StringToWString(const std::string& s);
std::string WStringToString(const std::wstring& s);
這兩個函數的目的就是寬字節和窄字節相互轉換。但是在轉換過程中對於編碼指定的問題導致轉換結果不對,從而導致寫入gdb文件中的中文屬性值亂碼。下面是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,將上述兩個函數修改爲如下:
/*************************************************************************/
/* 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;
}
修改完保存,重新編譯GDAL,如果使用的插件,直接編譯File GDB的插件dll,將生成的ogr_filegdb.dll放到gdal的插件目錄即可。在使用的時候,設置配置項FILEGDB_ENCODING=CP936(GBK)等即可。
命令行使用:--config FILEGDB_ENCODING CP936
代碼中使用:CPLSetConfigOption("FILEGDB_ENCODING", "CP936")