GDAL写入FileGDB中文属性乱码问题

2/22/2017来源:ASP.NET技巧人气:1898

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