GDAL库对于C#的支持问题还是蛮多的,对于中文路径的支持就是其中之一(另一个就是通过OGR库获取图形的坐标信息)。

关于C#支持中文路径,看过我之前博客的应该都不陌生,如果使用的是我修改过的GDAL库,可以通过设置下面的代码即可让C#直接支持中文路径。如果使用官方的库,不用设置直接应该就可以支持中文路径。

    // 注册所有的驱动Ogr.RegisterAll();// 为了支持中文路径,请添加下面这句代码OSGeo.GDAL.Gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8","YES");// 为了支持shp属性表字段支持中文,请添加下面这句OSGeo.GDAL.Gdal.SetConfigOption("SHAPE_ENCODING","");

昨天,一位朋友说,他测试C#版本,发现中文路径有时候可以,有时候不可以,通过设置GDAL_FILENAME_IS_UTF8也无济于事。

今天通过测试发现,只要是文件名中的汉字个数是偶数,完全没有影响,读取和创建都正常,如果文件名中的汉字个数是奇数,肯定不能读取和创建。

比如下面的文件名就是正常的:

 D:\\新建文件夹\\新建1.shpD:\\密云数据\\线分离的0.shp

而下面的肯定就是不行:

 D:\\新建文件夹\\新建的1.shpD:\\密云数据\\线分离0.shp

下面就通过C#程序调试GDAL库,找找原因。按照上篇博客中的跨语言调试的方式,在C#程序中的Open函数处设置断点,然后启动调试,程序在此处中断。

首先用一个GDAL库可以打开的正常路径进行测试,如下图所示。

接下来按F11键,进入swig封装的C#代码中,如下图所示。

在这里,我们发现了这样的代码。

  public static DataSourceOpen(string utf8_path, int update) {IntPtr cPtr =OgrPINVOKE.Open(System.Text.Encoding.Default.GetString(System.Text.Encoding.UTF8.GetBytes(utf8_path)),update);DataSource ret = (cPtr ==IntPtr.Zero) ? null : new DataSource(cPtr, true, ThisOwn_true());if(OgrPINVOKE.SWIGPendingException.Pending) throwOgrPINVOKE.SWIGPendingException.Retrieve();return ret;}

其中在调用OgrPINVOKE时,将路径进行了编码转换,核心代码如下:

System.Text.Encoding.Default.GetString(System.Text.Encoding.UTF8.GetBytes(utf8_path))

从代码可以看出,Swig首先将C#默认的字符串,使用UTF8的编码转换为默认的编码。上面的路径“ D:\新建文件夹\新建1.shp ”通过这句转换之后就变成了“ D:\鏂板缓鏂囦欢澶筡鏂板缓1.shp ”。而这个字符串传入GDAL库后,在文件gdal-1.10.0\port\cpl_vsil_win32.cpp中的函数VSIVirtualHandle*VSIWin32FilesystemHandler::Open( const char *pszFilename,   const char *pszAccess )中又进行了一次编码转换。如下图所示。

通过上图,可以发现,如果设置了GDAL_FILENAME_IS_UTF8=YES时,系统先将编码从UTF8转为UCS2编码。通过这句之后,发现路径又编程了原来的,如下图:

这样GDAL库就可以正常打开该文件。下面再看一个GDAL不能打开的路径重复上面的步骤,下面只截取关键位置的截图。

首先是在打开时设置断点,文件路径为“D:\新建文件夹\新建的1.shp

然后传入GDAL库中的路径通过转码变成了“D:\鏂板缓鏂囦欢澶筡鏂板缓鐨?.shp”。之后再通过GDAL库中的函数转为宽字节时称为了“D:\新建文件夹\新建çš?.shp”。如下图所示。

只要路径中出现了问号(?),这个路径肯定有问题,不管是不是乱码。所以这个路径肯定就打不开了。

通过上面的步骤,我们可以确定,C#的路径是好使的,而通过SWIG中的编码转换后就出现了问题,所以我们可以认为是编码转换出现的问题。

在SWIG封装的接口中,使用System.Text.Encoding.Default.GetString(System.Text.Encoding.UTF8.GetBytes(utf8_path))进行转换,下面针对此代码片段写一个简单的测试代码进行验证。

staticvoid Main(string[] args)
{string strUtf8 = "D:\\新建文件夹\\新建的1.shp";byte[] byutf8 =System.Text.Encoding.UTF8.GetBytes(strUtf8);string strDefault =System.Text.Encoding.Default.GetString(byutf8);byte[] byDefault =System.Text.Encoding.Default.GetBytes(strDefault);string strUtf8n = System.Text.Encoding.UTF8.GetString(byDefault);
}

首先看一个GDAL可以正常访问的路径,首先查看转换后再转回来,共三个字符串的对比,如下图,从图中可以看出,转换为Default再转为utf8之后,与原来的路径一样。所以GDAL库可以正常访问。

而转换前后获取的byte数组内容完全一致,如下图所示:

下面再使用一个GDAL不能访问的路径进行测试,查看转换后再转回来,共三个字符串的对比,如下图,从图中可以看出,转换为Default再转为utf8之后,与原来的路径发生了变化。

下面比较两次转换的byte数组,按理说内存中的byte数组应该是一样的,下面对比两个byte数组中的内容,如下图所示,从图中可以发现,数组转换前的27和28分别是132和49,而转换后,这两个字节变成了一个字节(63)。

从这里可以看出,可以认为问题就出在此处。对应ASCII码表,将上图中的值转为字符串,可以得到下面的图。英文字符占用一个byte,而汉字占用3个byte。而在转码的时候应该是两个字节为一组进行转码处理,也就是说对于偶数个汉字,转成byte是3倍的偶数,结果肯定是偶数,所以按照两个字节转码刚好可以转完;而汉字为奇数个,转成byte是3倍的奇数,结果肯定是个奇数,按照两个字节转码,肯定会多出来一个,这多出来的一个系统可能不认识就用问号(?)来表示了。

所以,可以这么认为,汉字是偶数的就正常,奇数的就会出现问题,与GDAL表现的结果完全一致。上面的最后这一段的是我个人的分析,不代表微软内部就是这么实现的。或许这可能算作C#的一个bug?不知道微软有没有发现这个问题。

浅析GDAL库C#版本支持中文路径问题相关推荐

  1. 浅析GDAL库C#版本支持中文路径问题(续)

    上篇博客中主要说了GDAL库C#版本中存在的问题,其表现形式主要是:"文件名中的汉字个数是偶数,完全没有影响,读取和创建都正常,如果文件名中的汉字个数是奇数,读取和创建都会报错." ...

  2. GDAL支持中文路径-属性表支持中文配置

    // 为了支持中文路径 OSGeo.GDAL.Gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "YES"); // ...

  3. 使用SQLite3支持中文路径

    最近编写控制点库的几何精校正中使用SQLite来管理控制点,在使用过程中发现SQLite发现不支持中文路径,打开中文路径的数据库在查询的时候提示"no such table: ***&quo ...

  4. 解决Mygui不支持中文路径

    昨日不可追, 今日尤可为.勤奋,炽诚,不忘初心 外国人写的Mygui库,不支持中文路径,情有可原,中文编码嘛,中国的标准,对吧. 但是! 中国那么多用Mygui的大虾呢?网上居然找不到一篇博客是解决M ...

  5. opencv中的imread不支持中文路径的解决办法

    其实严格来说,不是imread不支持中文路径,而是不支持non-ascii.所以不论路径如何转换编码格式,应该都不能解决问题. 解决的思路就是先用其他支持中文的API,把图片数据导入到内存中,然后通过 ...

  6. svn不支持中文路径问题的解决

    作者:朱金灿 来源:http://blog.csdn.net/clever101 svn的授权文件authz默认是不支持中文路径的,因此在精确控制中文文件夹的授权时往往会出错.要解决这个问题,需要用U ...

  7. java压缩解压缩_利用Java实现压缩与解压缩(zip、gzip)支持中文路径

    zip扮演着归档和压缩两个角色:gzip并不将文件归档,仅只是对单个文件进行压缩,所以,在UNIX平台上,命令tar通常用来创建一个档案文件,然后命令gzip来将档案文件压缩. Java I/O类库还 ...

  8. nginx文件服务器中文路径,nginx配置文件支持中文路径.htm

    nginx配置文件支持中文路径 nginx配置文件支持中文路径 例子: server { color=#ff0000>charset utf-8; listen 8088;         se ...

  9. 使GDAL库支持中文路径或中文文件名的处理方法

    之前生成的gdal 2.1.1动态库,在通过命令行执行时,遇到有中文路径或中文图像名时,GDALOpen函数不能正确的被调用,如下图: 解决方法: 1.      在所有使用GDALAllRegist ...

最新文章

  1. 当谈论迭代器时,我谈些什么?
  2. 《 线性代数及其应用 (原书第4版)》—— 2.3 可逆矩阵的特征
  3. 43 | 发挥人的潜能:探索式测试
  4. shell 循环判断语法
  5. azkaban修改MySQL配置上传包的大小上限
  6. boost::unique_copy相关的测试程序
  7. 2012 Java陷阱
  8. 对象的序列化流_ObjectOutputStream
  9. 08 redis数据类型:hash
  10. 前端学习(1989)vue之电商管理系统电商系统之渲染商品列表数据
  11. WPF多线程UI更新——两种方法
  12. python分析工具有哪些_常用Python数据分析工具汇总
  13. 联通sgip协议 java socket_sgip12 个人编写的 联通SGIP协议基于 socket 方式实现 源 联合开发网 - pudn.com...
  14. tomcat8+idea远程调试
  15. RVC使用指南(四)-集群状况
  16. 使用这个,自定义AlertDialog在你手里都不是问题
  17. Dialogue and Conversational Agents
  18. 校园信息发布平台网站源码
  19. 安全防御——防病毒网关
  20. CAN学习笔记一:DBC文件创建

热门文章

  1. html select 样式t调整_用纯css改变下拉列表select框的默认样式
  2. jframe大小根据组件变化_Swing JDialog容器和JFrame容器使用教程
  3. 蓝牙:CRC原理详解(附crc16校验代码)
  4. 洛谷——P1046 [NOIP2005 普及组] 陶陶摘苹果
  5. mysql之查询前几条或者中间某几行数据
  6. joomla添加html,如何将自定义html代码添加到Joomla 2.5菜单项?
  7. 打开android studio项目,为什么我们没有一个文件来打开Android Studio项目?
  8. pyaudio usb playback_电脑USB接口怎么禁用?系统禁用USB端口的两种方法
  9. IOS 状态栏 显示与隐藏网络活动状态
  10. 关于Python常见功能使用的博客收藏