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.shp
D:\\密云数据\\线分离的0.shp

而下面的肯定就是不行:

	D:\\新建文件夹\\新建的1.shp
D:\\密云数据\\线分离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支持中文路径和Shp文件中文属性写入

    在使用GDAL的过程中,为了支持中文,比需手动进行中文路径的设置,同时特别是在对Shp的属性进行中文输入的时候,都必须进行必要的设定. 为了支持中文路径,在注册了驱动之后,加上第三句就可以了.必须设置 ...

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

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

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

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

  5. 解决tomcat不支持中文路径的问题

    问题描述: 开发文件下载功能时,因为需求比较简单,要求下载一个说明文件.于是,直接给出了文件所在服务器的地址,通过链接直接下载此文件(因需求简单,未考虑安全方面的问题-_-||). 在这个过程中,文件 ...

  6. 【转】让apache支持中文路径或者中文文件

    本帖最后由 狂人阿川 于 2013-4-12 19:13 编辑 今天在给一美国VPS客户调试他的程序的时候.发现他的网站有中文名称.貌似apache无法认识中文路径,火狐下面能下载他的文件,IE下面不 ...

  7. Unity3D 原来Unity比较新的版本支持中文

    注意: Unity 2018.2 以上版本才可以

  8. Jenkins的FTP上传插件Publish Over FTP Plugin设置支持中文路径

    [系统管理]->[系统设置]->[Publish over FTP]->[Control encoding]->输入[GB2312]或者[UTF-8]

  9. ImageMaigck不支持中文路径的问题

    不知道咋回事. 回顾下: char* pTest1 = "测试.txt"; wchar_t* pTest2 = L"测试.txt"; 以上是pTest1指向的内 ...

随机推荐

  1. springMVC源码分析--ViewResolver视图解析器(一)

    SpringMVC用于处理视图最重要的两个接口是ViewResolver和View.ViewResolver的主要作用是把一个逻辑上的视图名称解析为一个真正的视图,SpringMVC中用于把View对 ...

  2. VirtualBox: How to config higher screen resolution

    Issue: Default Screen Resolution in Virtualbox instance is 800*600 which might be too small for gene ...

  3. Android Multimedia框架总结(十二)CodeC部分之OMXCodec与OMX事件回调流程

    转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52629449 前言:上篇文中分析 ...

  4. maven的UnsupportedClassVersionError

    问题描述 我安装了maven3.3.3,配置好了M2_HOME和path环境变量之后,执行mvn -v报错:java.lang.UnsupportedClassVersionError: -. : U ...

  5. Dynamics CRM2016 业务流程之Task Flow(一)

    Task Flow 属于CRM移动端的特性,如果在项目实施中用不到CRM自带的APP或者对自APP不感冒的,那就没有往下看的必要了,移步吧. 该功能默认是不开启的,需要我们去系统设置中开启它,打勾,选 ...

  6. UE4 C++与蓝图交互

    一.C++调用蓝图的函数 本来应该有一个很好的示例,但一下却忘了适用于哪些地方,只有简单写一个步骤了. 1.新建一个C++类继承Actor,名称随意,我这里继承了一个SplineMesh,一样de,并 ...

  7. Android中利用Camera与Matrix实现3D效果详解

    本文行文目录: 一.Camera与Matrix初步认识 二.Camera与Matrix旋转效果拆分介绍 三.Camera与Matrix实现立体3D切换效果 [csdn地址:http://blog.cs ...

  8. malloc、calloc、relloc

    1.malloc void * malloc(size_t _Size); malloc函数在堆中分配参数_Size指定大小的内存,单位:字节,函数返回void *指针. 2.calloc void ...

  9. javascript之event对象

    注意:以下给出的是在IE下的event事件说明,如果应用在非IE下可能会出现兼容性问题,需要结合具体的应用环境,使用兼容性的函数来处理 1.altKey 描述: 检查alt键的状态. 语法: even ...

  10. UNIX网络编程——带外数据

    许多传输层有带外数据的概念,它有时也称为经加速数据.其想法是一个连接的某端发生了重要的事情,而且该端希望迅速通告其对端.这里"迅速"意味着这种通知应该在已排队等待发送的任何&quo ...