直接说结论:
windows对多语言环境中的特殊字符并不完备,总有支持不到的地方,所以,建议禁止路径中出现非常规的六种横杠,仅允许英文横杠(-)(0x2D)。
此网页对编码总结比较到位:
https://blog.csdn.net/Liuqz2009/article/details/107861408
后面是个人的测试笔记
7种横杠:-‐‑‒–—― 第一个是英文ASCII码-(0x2D),其他为unicode 0x2010~0x2015
UTF16BE: FE FF 00 2D 20 10 20 11 20 12 20 13 20 14 20 15 unicode大尾
UTF16LE: FF FE 2D 00 10 20 11 20 12 20 13 20 14 20 15 20 unicode小尾
UTF8: 2D E2 80 90 E2 80 91 E2 80 92 E2 80 93 E2 80 94 E2 80 95 (3字节连续对应)
UTF8BOM: EF BB BF 2D E2 80 90 E2 80 91 E2 80 92 E2 80 93 E2 80 94 E2 80 95 (3字节连续对应)
ANSI: 2D A9 5C 3F 3F A8 43 A1 AA A8 44; -‐??–—― 第3(?0x2011)、4(?0x2012)个横杠在当前CP936简体中文系统无对应。3F为?号。
windows10简体中文系统创建txt默认是UTF8文件,对7种-进行mkdir(bat脚本),只有一种执行成功。
如果在cmd中挨个执行,成功5次
mkdir - 成功:0x2D
mkdir ‐
mkdir ?
mkdir ?
mkdir – 失败:子目录或文件 - 已经存在。 0x2013 (mkdir时失败,但鼠标右键可以创建)识别为了0x2D目录
mkdir — 失败:子目录或文件 - 已经存在。 0x2014 (mkdir时失败,但鼠标右键可以创建)识别为了0x2D目录
mkdir ―
cmd中显示都正常,unicode或utf8显示。
tree > 1.txt 导出的是ANSI文件,两个无法正常显示(说明资源浏览器不是ANSI)
├─- 0x2D
├─‐ 0x2010
├─? 0x2011 显示失败,但可以拷贝到UTF16BE文件中
├─? 0x2012 显示失败,但可以拷贝到UTF16BE文件中
└─― 0x2015
最终正常的只有0x2D、0x2010、0x2015
中文输入法(sogo)中文横杠对应的是0x2014 (mkdir时失败,但鼠标右键可以创建)
├─- 0x2D
├─‐ 0x2010
├─? 0x2011 显示失败,但可以拷贝到UTF16BE文件中
├─? 0x2012 显示失败,但可以拷贝到UTF16BE文件中
├─– 0x2013
├─— 0x2014
└─― 0x2015
以下拷贝命令全部执行成功,但实际有两个目录为空,说明重复拷贝了两次,与mkdir失败一致(0x2013、0x2014)
copy /Y 1utf8bom.txt - 0x2D
copy /Y 1utf8bom.txt ‐
copy /Y 1utf8bom.txt ?
copy /Y 1utf8bom.txt ?
copy /Y 1utf8bom.txt – 重复拷贝到了0x2D目录
copy /Y 1utf8bom.txt — 重复拷贝到了0x2D目录,中文输入法(sogo)中文横杠对应的是0x2014
copy /Y 1utf8bom.txt ― 0x2015
结论:
1、QT5.5.1 QFile copy对中文横杠失败的根源在于windows10简体中文系统不支持目录含有0x2013、0x2014的目录拷贝。
2、ANSI对于显示0x2011、0x2012也不正常,所以至少要剔除0x2011~0x2014共4种横杠。
3、对于0x2010、0x2015,不清楚怎么通过输入法敲出来,也没有意义。(中文环境输出0x2D、0x2014)
4、最终建议禁止目录或文件路径中出现0x2010~0x2015六种横杠。
5、横杠只允许出现英文0x2D(-)。禁止其他所有横杠。
相关检查代码
bool CheckPath(const std::string &str_path)
{
//假定输入为windows local编码CP936 GBK版本
if (str_path.length() == 0)
{
return false;
}
//即使部分windows函数能访问部分目录,但不是所有功能都正常,所以access判断没必要。
//if (access(str_path.c_str(), 0) == 0)
//{
// return true;//存在的都正常,可能是文件,也可能是目录
//}
#pragma warning(push)
#pragma warning(disable:4566) //本句没有必要了,暂时保留。
#pragma execution_character_set("utf-8") //没有此句,strUtf8会被编译为ANSI
const static std::string strUtf8 = "‐,?,?,–,—,―"; //warning C4566: 由通用字符名称“\u2011”表示的字符不能在当前代码页(936)中表示出来
#pragma warning(pop)
//const static std::string strUtf8 = "‐,–,—,―"; //删除编译告警的两种横杠(0x2011)、(0x2012)
//const static std::string strGB2312 = ToLocal(strUtf8);
const static string_vec strUtf8_vec = split(strUtf8, ",");
const std::string str_path_utf8 = ToUtf8(str_path);//ANSI 0xA1AA ==> UTF8 0xE28095 (UTF16BE 0x2015)这里说明iconv转换也不一定标准。
for each (const std::string &strUtf8_temp in strUtf8_vec)
{
//const char *pCharTemp = strGB2312_temp.c_str();//测试,此处为ANSI编码A95C、A843、A1AA、A844。
//const char *pCharTemp = strUtf8_temp.c_str();//测试,此处为utf8编码0xE28090 ~ 0xE28095
if (str_path_utf8.find(strUtf8_temp) != std::string::npos)
{
return false;
}
}
return true;
}
以上有乱码是由于拷贝过程导致的,实际可以在unicode BE txt中编辑二进制数据获得7种横杠。
-‐‑‒–—―