GDAL读取S-57海图数据中文属性值乱码问题解决

使用GDAL读取S-57海图数据时,对于属性表中的中文属性值读出来是乱码。如图1所示。


图1 S57海图数据中文乱码字段

通过调试代码发现,S-57文件中的中文是按照宽字节存储在文件中,而GDAL在读取时统一按照单字节来读取,这样就直接导致了中文属性值的乱码。比如这里有个字段属性值为“北京市”,读出来显示为“S琋^”,对应的十六进制为“0x17 0x53 0xac 0x4e 0x02 0x5e 0x1f 0x00”。

本以为GDAL中会有个设置选项来设置编码,S57的源码翻遍了也没找到设置选项,看来只能自力更生了,那就是自己写个转换函数来进行转换。修改GDAL库的源码工作量有点大,还是直接在外面处理吧。首先我们要写一个把宽字节转为单字节的函数。代码如下:

string ConvertWchar2Char(const wstring &str)
{
	size_t len = wcstombs(NULL, str.c_str(), 0)*2 + 1;
	char *pszDst = new char[len];

	setlocale(LC_ALL,"");     //设置本地默认Locale
	int len1 = wcstombs(pszDst, str.c_str(), len);
	setlocale(LC_ALL,"C");     //默认

	if(len1 == -1)
	{
		delete []pszDst;
		throw runtime_error("wcstombs(): unable to convert character");
	}

	string strChar = string(pszDst, len);
	delete []pszDst;
	return strChar;
}
有了上面的函数,我们就可以在读取属性值后,调用上面的函数进行转换就OK了。需要注意的是,GDAL中获取的属性值返回值是一个const char*格式,表面看起来是个单字节,但实质内存存储的确是多字节,所以我们需要强制类型转换转为多字节,代码片段如下:

	const char* pszValue = poFeature->GetFieldAsString("NOBJNM");
	wstring strwValue = (const wchar_t*)pszValue;

	//转换为单字节
	string strValue = ConvertWchar2Char(strwValue);

第一句返回的是一个const char*,然后直接强制类型转为const wchar_t*类型,然后构造一个wstring类型。最后使用上面的函数进行转换即可得到最终的结果值。完整的测试代码如下:

#include <stdio.h>
#include <string>

#include "ogrsf_frmts.h"
#include "ogr_spatialref.h"

using namespace std;

string ConvertWchar2Char(const wstring &str)
{
	size_t len = wcstombs(NULL, str.c_str(), 0)*2 + 1;
	char *pszDst = new char[len];

	setlocale(LC_ALL,"");     //设置本地默认Locale
	int len1 = wcstombs(pszDst, str.c_str(), len);
	setlocale(LC_ALL,"C");     //默认

	if(len1 == -1)
	{
		delete []pszDst;
		throw runtime_error("wcstombs(): unable to convert character");
	}

	string strChar = string(pszDst, len);
	delete []pszDst;
	return strChar;
}

int ReadS57()  
{  
	CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "NO");  
	OGRRegisterAll();  


	//打开数据  
	const char* pszS57 = "D:\\C1100102.000";  
	OGRDataSource *poDS = OGRSFDriverRegistrar::Open(pszS57, FALSE );  
	if( poDS == NULL )  
	{  
		printf( "Open failed.\n" );  
		return 1;  
	}  


	// 获取有中文属性值的图层  
	OGRLayer *poLayer = poDS->GetLayerByName( "BUAARE" );  
	if( poLayer == NULL )  
	{  
		printf( "Get Layer failed.\n" );  
		OGRDataSource::DestroyDataSource( poDS );  
		return 1;  
	}  


	poLayer->ResetReading();  
	OGRFeature *poFeature = poLayer->GetNextFeature();  
	while (poFeature != NULL )  
	{  
		OGRFeatureDefn *poFDefn = poLayer->GetLayerDefn();   //获取属性字段值  


		// 为了演示说明,就只输出乱码的属性值  
		string strValue = poFeature->GetFieldAsString("NOBJNM"); 


		if (strValue != "")
		{
			char* pszValue = (char*)strValue.c_str();
			size_t ilast = strlen(pszValue);
			pszValue[ilast-1] = '\0';
			wstring strwValue = (const wchar_t*)pszValue;  


			//转换为单字节  
			strValue = ConvertWchar2Char(strwValue);  
		}


		printf("%s\n", strValue.c_str());  


		OGRFeature::DestroyFeature( poFeature );  
		poFeature = poLayer->GetNextFeature();  
	}  


	OGRDataSource::DestroyDataSource( poDS );  
	return 0;  
}

int main()
{
	// 先测试转换函数是否正常工作
	const char* pszValue = "S琋^";
	wstring str =  (const wchar_t*)pszValue;
	string strTemp = ConvertWchar2Char(str);
	printf("%s\n", strTemp.c_str());

	wstring str1 = L"Hello1234";
	strTemp = ConvertWchar2Char(str1);
	printf("%s\n", strTemp.c_str());

	// 读取S57海图数据
	ReadS57();

	return 0;
}

转载于:https://www.cnblogs.com/xiaowangba/archive/2013/04/24/6313961.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值