1. 正文

最近在使用GDAL读写Shp格式中的属性字段的时候也遇到了中文乱码的问题,总结下自己遇到的情况。

1.1. shp文件本身的编码的问题

应该是由于shp格式加入了对宽字符的支持,所以导致有段时间的shp文件和ArcGIS是存在不匹配的问题,所以在网上搜索资源的时候遇到了大量的关于ArcMap显示shp属性表出现乱码的问题。现在的shp格式的文件应该已经稳定下来了,新添加了一个.cpg的文件,里面保存着属性表的编码格式:

图1-1:shp格式的.cpg文件

从ArcGIS10.2开始,只要是属性表编码与.cpg文件记录的编码方式一致,就不会再有显示乱码的问题。网上查询到的修改注册表的方法,我在ArcGIS10.2中试过,似乎已经不再起效了。

那么对于没有.cpg或者的情况,应该可以看属性表.dbf文件。如果编码方式正确,这个文件用文本编辑器打开是可以看到正常的中文的:

图1-2:shp格式的.dbf文件

在正常显示中文情况下,可以查看下文件的编码方式:

图1-3:查看编码方式

当然,如果遇到乱码,可以尝试用别的编码方式打开,这样你就能知道属性表具体是什么编码了。对于国内的情况来说,只有ANSI编码和UNICODE编码两种:其中简体中文系统中ANSI编码就是GB2312编码;UTF-8是UNICODE编码的一种具体实现。

1.2. 设置读取的编码方式

1.2.1. GDAL设置

可以通过全局设置函数CPLSetConfigOption(),来配置读取Shp文件的读取编码。例如对于简体中文系统中ANSI编码,可以设置为GBK:

CPLSetConfigOption("SHAPE_ENCODING","GBK");

上面这种方式是全局设置的,如果想设置单个文件的编码方式也是可以的。例如,打开一个矢量文件读取为UTF-8的数据集:

char** ppszOptions = NULL;
ppszOptions = CSLSetNameValue(ppszOptions, "ENCODING", "UTF-8");
GDALDataset *poDS = (GDALDataset*)GDALOpenEx(filePath.c_str(), GDAL_OF_VECTOR, NULL, ppszOptions, NULL);

网上提供的解决方案都是将编码方式设置为空[1],这种方式应该更具有通用性,起码我这里读取GBK和UTF-8格式的Shp的格式都是可以的:

CPLSetConfigOption("SHAPE_ENCODING","");

1.2.2. 解码方式

如果读取出来的字段属性仍然是乱码,就应该考虑字符串的解码问题,就是获取的字段属性字符串没有正确的解码出来。例如读取UTF-8的Shp文件的属性字段:

OGRFeature *poFeature;
while ((poFeature = poLayer->GetNextFeature()) != NULL)
{
OGRGeometry *pGeo = poFeature->GetGeometryRef();
OGRwkbGeometryType pGeoType = pGeo->getGeometryType(); //
OGRFeatureDefn *poFDefn = poLayer->GetLayerDefn();
int n = poFDefn->GetFieldCount(); //获得字段的数目,不包括前两个字段(FID,Shape);
for (int iField = 0; iField <n; iField++)
{
//输出每个字段的值
//cout << poFeature->GetFieldAsString(iField) << " ";
cout << UTF8_To_string(poFeature->GetFieldAsString(iField)) << " ";
}
//cout << endl; OGRFeature::DestroyFeature(poFeature);
}

默认情况下,cout是无法正确打印输出UTF-8字符编码的,通过UTF8_To_string这个函数,将UTF-8编码的字符串转换成本地ANSI编码,也就是GBK编码字符串,就可以正确输出显示了。附带一下两者的转换函数[2]

// UTF8转std:string
// 转换过程:先将utf8转双字节Unicode编码,再通过WideCharToMultiByte将宽字符转换为多字节。
std::string UTF8_To_string(const std::string& str)
{
int nwLen = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, NULL, 0);
wchar_t* pwBuf = new wchar_t[nwLen + 1]; //一定要加1,不然会出现尾巴
memset(pwBuf, 0, nwLen * 2 + 2);
MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.length(), pwBuf, nwLen);
int nLen = WideCharToMultiByte(CP_ACP, 0, pwBuf, -1, NULL, NULL, NULL, NULL);
char* pBuf = new char[nLen + 1];
memset(pBuf, 0, nLen + 1);
WideCharToMultiByte(CP_ACP, 0, pwBuf, nwLen, pBuf, nLen, NULL, NULL); std::string strRet = pBuf; delete []pBuf;
delete []pwBuf;
pBuf = NULL;
pwBuf = NULL; return strRet;
} // std:string转UTF8
std::string string_To_UTF8(const std::string& str)
{
int nwLen = ::MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, NULL, 0);
wchar_t* pwBuf = new wchar_t[nwLen + 1]; //一定要加1,不然会出现尾巴
ZeroMemory(pwBuf, nwLen * 2 + 2);
::MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.length(), pwBuf, nwLen);
int nLen = ::WideCharToMultiByte(CP_UTF8, 0, pwBuf, -1, NULL, NULL, NULL, NULL);
char* pBuf = new char[nLen + 1];
ZeroMemory(pBuf, nLen + 1);
::WideCharToMultiByte(CP_UTF8, 0, pwBuf, nwLen, pBuf, nLen, NULL, NULL); std::string strRet(pBuf); delete []pwBuf;
delete []pBuf;
pwBuf = NULL;
pBuf = NULL; return strRet;
}

1.2.3. 其他

还有个值得注意的问题就是Shp格式的属性字段名称的长度最大只能支持10个字符。如果采用UTF-8编码,可能用不了几个中文字符就被截断了,这个时候属性字段名称也可能存在乱码。

2. 参考

[1] GDAL/OGR 1.9.0获取shp文件中中文字段值和属性值乱码文件解决

[2] UTF8与std:string互转

关于GDAL读写Shp乱码的问题总结的更多相关文章

  1. python GDAL 读写shp文件

    gdal包用于处理栅格数据,ogr用于处理矢量数据. 1 #!C:\Program Files\pythonxy\python\python.exe 2 #-*- coding:gb2312 -*- ...

  2. C#、C++用GDAL读shp文件(转载)

    C#.C++用GDAL读shp文件 C#用GDAL读shp文件 (2012-08-14 17:09:45) 标签: 杂谈 分类: c#方面的总结 1.目前使用开发环境为VS2008+GDAL1.81 ...

  3. GDAL 生成shp文件

    附件:http://pan.baidu.com/s/1i3GPwrV(C#版GDAL接口.dll) 示例程序: http://pan.baidu.com/s/1jpIKQ  (程序是在vs2008 x ...

  4. ArcEngine和GDAL读写栅格数据机制对比(一)

    最近应用AE开发插值和栅格转等值线的程序,涉及到栅格读写的有关内容.联想到ArcGIS利用了GDAL的某些东西,从AE的OMD中也发现RasterDataset和RasterBand这些命名和GDAL ...

  5. java 读写文件乱码问题

    这样写,会出现乱码.原因是文件时gbk格式的, BufferedReader br = new BufferedReader(new FileReader(indir)); BufferedWrite ...

  6. java(IO)读写文件乱码转换UTF-8问题

    java(IO)读写文件乱码转换UTF-8问题 读取文件 String Content = ""; // 文件很长的话建议使用StringBuffer try { FileInpu ...

  7. gdal读写图像分块处理

    转自赵文原文 gdal读写图像分块处理(精华版) Review: 用gdal,感觉还不如直接用C++底层函数对遥感数据进行处理.因为gdal进行太多封装,如果你仅仅只是Geotif等格式进行处理,IO ...

  8. GDAL读取Shp问题解决:Unable to open EPSG support file gcs.csv

    在GIS软件的开发中,经常用到开源库GDAL读取Shp数据,当shp数据中包含投影信息时,可能会遇到“Unable to open EPSG support file gcs.csv”错误提示,该错误 ...

  9. Java 使用GDAL 读写 shapefile

    读取shp文件,并把它转化为json import org.gdal.ogr.*; import org.gdal.ogr.Driver; import org.gdal.gdal.*; public ...

随机推荐

  1. Windows系统调用中API从3环到0环(下)

     Windows内核分析索引目录:https://www.cnblogs.com/onetrainee/p/11675224.html Windows系统调用中API从3环到0环(下) 如果对API在 ...

  2. Linux系统基础

    Linux系统基础 目录   简介 0x01 Linux文件与目录管理 0x02 Linux系统用户以及用户组管理 0x03文档的压缩与打包 0x04 apt安装软件 0x05 进程管理 标签 Lin ...

  3. 对新手严重不友好的强者——Nginx那些俯拾皆是的坑

    1.if和后边的括号要隔一个空格,变量后面也要有空格. 2.location / 和location = / 的意味不一样.前面的是通用匹配,后面的匹配根节点访问请求,前面的使用不好很容易引发重定向过 ...

  4. NDN helper 学习记录

    1.StackHelper 主要用于在请求的节点上安装ndnSIM网络堆栈, 提供一种简单的方法来配置NDN模拟的几个重要参数.(官方解释) 其实就是给结点装上堆栈 方法: 全部结点一次性安装(比较常 ...

  5. 移动端前端常见的触摸相关事件touch、tap、swipe

    前端的很多事件在PC端和浏览器端可公用,但有些事件却只在移动端产生,如触摸相关的事件 本文整理了移动端常见的一些事件,包括原生支持的click.touch.tap.swipe事件,也有定义型的gest ...

  6. win10-搭建git工具

    .下载安装 git .生成 SSH 密钥 ssh-keygen -t rsa -C "email@com" -b 4096 .配置gitlab 增加 SSH 密钥. .配置 git ...

  7. libevent::事件

    /***************************************************************** 函数功能: 创建事件集 ********************* ...

  8. PHP实现阿里云OSS文件上传(支持批量)

    上传文件至阿里云OSS,整体逻辑是,文件先临时上传到本地,然后在上传到OSS,最后删除本地的临时文件(也可以不删,具体看自己的业务需求),具体实现流程如下:   1.下载阿里云OSS对象上传SDK(P ...

  9. ESP8266开发之旅 基础篇⑤ ESP8266 SPI通信和I2C通信

        设备与设备之间的通信往往都伴随着总线的使用,而用得比较多的就当属于SPI总线和I2C总线,而恰巧NodeMcu也支持这两种总线通信,所以本章的主要内容就是讲解ESP8266 SPI和I2C总线 ...

  10. Codeblocks 等软件 修改源代码后 不能立即执行的解决办法||exe文件删除慢

    不懈地奋斗了两天,终于找到原因了. 记录如下 症状: Codeblocks .Visual Studio 都出现此问题:修改源代码 无法立即执行 ,就是:cannot open output file ...