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:

  1. CPLSetConfigOption("SHAPE_ENCODING","GBK");

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

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

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

  1. CPLSetConfigOption("SHAPE_ENCODING","");

1.2.2. 解码方式

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

  1. OGRFeature *poFeature;
  2. while ((poFeature = poLayer->GetNextFeature()) != NULL)
  3. {
  4. OGRGeometry *pGeo = poFeature->GetGeometryRef();
  5. OGRwkbGeometryType pGeoType = pGeo->getGeometryType();
  6. //
  7. OGRFeatureDefn *poFDefn = poLayer->GetLayerDefn();
  8. int n = poFDefn->GetFieldCount(); //获得字段的数目,不包括前两个字段(FID,Shape);
  9. for (int iField = 0; iField <n; iField++)
  10. {
  11. //输出每个字段的值
  12. //cout << poFeature->GetFieldAsString(iField) << " ";
  13. cout << UTF8_To_string(poFeature->GetFieldAsString(iField)) << " ";
  14. }
  15. //cout << endl;
  16. OGRFeature::DestroyFeature(poFeature);
  17. }

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

  1. // UTF8转std:string
  2. // 转换过程:先将utf8转双字节Unicode编码,再通过WideCharToMultiByte将宽字符转换为多字节。
  3. std::string UTF8_To_string(const std::string& str)
  4. {
  5. int nwLen = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, NULL, 0);
  6. wchar_t* pwBuf = new wchar_t[nwLen + 1]; //一定要加1,不然会出现尾巴
  7. memset(pwBuf, 0, nwLen * 2 + 2);
  8. MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.length(), pwBuf, nwLen);
  9. int nLen = WideCharToMultiByte(CP_ACP, 0, pwBuf, -1, NULL, NULL, NULL, NULL);
  10. char* pBuf = new char[nLen + 1];
  11. memset(pBuf, 0, nLen + 1);
  12. WideCharToMultiByte(CP_ACP, 0, pwBuf, nwLen, pBuf, nLen, NULL, NULL);
  13. std::string strRet = pBuf;
  14. delete []pBuf;
  15. delete []pwBuf;
  16. pBuf = NULL;
  17. pwBuf = NULL;
  18. return strRet;
  19. }
  20. // std:string转UTF8
  21. std::string string_To_UTF8(const std::string& str)
  22. {
  23. int nwLen = ::MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, NULL, 0);
  24. wchar_t* pwBuf = new wchar_t[nwLen + 1]; //一定要加1,不然会出现尾巴
  25. ZeroMemory(pwBuf, nwLen * 2 + 2);
  26. ::MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.length(), pwBuf, nwLen);
  27. int nLen = ::WideCharToMultiByte(CP_UTF8, 0, pwBuf, -1, NULL, NULL, NULL, NULL);
  28. char* pBuf = new char[nLen + 1];
  29. ZeroMemory(pBuf, nLen + 1);
  30. ::WideCharToMultiByte(CP_UTF8, 0, pwBuf, nwLen, pBuf, nLen, NULL, NULL);
  31. std::string strRet(pBuf);
  32. delete []pwBuf;
  33. delete []pBuf;
  34. pwBuf = NULL;
  35. pBuf = NULL;
  36. return strRet;
  37. }

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. vue中methods,computed,filters,watch的总结

    08.28自我总结 vue中methods,computed,filters,watch的总结 一.methods methods属性里面的方法会在数据发生变化的时候你,只要引用了此里面分方法,方法就 ...

  2. postman环境变量设置

    1.点击小齿轮进入到环境变量添加页面,点击add添加环境变量 2.输入变量名称和变量值 3.添加成功 4.接口中设置变量

  3. 【RT-Thread】线程的基本知识

    什么是线程? 人们在生活中处理复杂问题时,惯用的方法就是分而治之,即把一个大问题分解成多个相对简单.比较容易解决的小问题,小问题逐个被解决了,大问题也就随之解决了.同样,在设计一个较为复杂的应用程序时 ...

  4. 介绍ArcGIS中各种数据的打开方法——shp(矢量文件)

    2.加载shp文件到地图控件 ShapeFile是一种矢量数据模型的计算机数据组织文件,用于在计算机上表达矢量数据的计算机文件. 加载ShapeFile文件最主要是:axMapControll控件对象 ...

  5. (19)ASP.NET Core EF创建模型(包含属性和排除属性、主键、生成的值)

    1.什么是Fluent API? EF中内嵌的约定将POCO类映射到表.但是,有时您无法或不想遵守这些约定,需要将实体映射到约定指示外的其他对象,所以Fluent API和注解都是一种方法,这两种方法 ...

  6. 渗透测试-基于白名单执行payload--Forfiles

    0x01 Forfiles简介: Forfiles为Windows默认安装的文件操作搜索工具之一,可根据日期,后缀名,修改日期为条件.常与批处理配合使用. 微软官方文档:https://docs.mi ...

  7. 后台模板引擎ejs与前台模板引擎artTemplate的简单介绍

    动态网页是指前端页面当中的数据内容来源于后台数据库,前端的html代码会随着后台数据的变化而变化,是动态生成的.制作动态网页有两种方式,一种方式是在后台拿到前端的html模板,利用后台模板引擎(如ej ...

  8. ndnsim安装遇到的一些问题

    我是安装的Ubuntu18.04+ndnsim2.7 由于最新版ndnsim的可视化与Python不兼容,出现了一些问题 1. No visualization support (cannot imp ...

  9. 全面认识nslookup命令及子命令

  10. 数据结构(二十七)Huffman树和Huffman编码

    Huffman树是一种在编码技术方面得到广泛应用的二叉树,它也是一种最优二叉树. 一.霍夫曼树的基本概念 1.结点的路径和结点的路径长度:结点间的路径是指从一个结点到另一个结点所经历的结点和分支序列. ...