GDAL寫入FileGDB中文屬性亂碼問題

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")

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章