最近在修改一个使用Window 给FTP服务器上传中文路径的问题,头疼了很久。

从Windows读取到的字符在遇到中文个数为奇数的时候,路径会被部分识别为乱码。而中文个数为偶数个,则能正常识别出来。

以下是在网上看到某位大牛分析的原因,看了才知道,原来是java输出流搞的鬼。

引用:

最近被utf-8搞得各种头痛。差点就要练出肉眼看二进制编码的火眼金睛。先举个今天遇到的小问题吧。
java用gbk方式写入的文件,似乎有个特性,是会自动把gbk编码中不能识别的0×0这个字节,替换成”?”,也即0x3F。这原本也没什么,但当他读取utf8文本并重新写入新的文件的时候,就会出现偏差。
众所周知,utf8编码的英文和符号部分是同ASCII编码兼容的。同时,在大多数中文中,很少出现0×0这样的字节。因此,用ASCII硬写utf8编码的中英混合文字,然后这个文件再用utf8的方式打开,运气好的话居然可以侥幸蒙混过关,毫无错误。然而,一旦文字中出现了带有0×0字节的utf8编码,就没那么侥幸了。
例如“个性”的性字,其unicode编码为0×6027, 翻译成utf8的话:


性
 60	    27
 01100000   00100111
[1110]0110 [10]000000 [10]100111
 E6	    80	       A7


这里用方括号标识了utf8的字节头,方便辨识。在windows上是使用小端序,所以实际的序列会是这样:

0110 1110 0000 1000 0111 1010


这里第三个字节出现了0×0,悲剧发生了,被java的流输出不知怎么就那么智能替换成了”?”


0110 1110 1111 0011 ...
6    E    F    3


结果这里就乱码了。打出来内容一团糟。变成“个<E6>?”。

另外一个曾让我头疼一天的问题,就是根据utf8编码规则,并不会出现0xC0 0×80这个双字。因为如果按照编码规范


0xC0           0x80
[110]0 0000    [10]00 0000
 0000  0000


这根本就是0×0嘛!不可能编码成这个样子的。wiki上查了半天才发现,原来这个又是windows的专有解决方案。完全是windows系统一厢情愿,想要区别于一般的ASCII文本而作的别扭事。结果这样的文本想要插入到mysql数据库时,就会被数据库认为是不合理的utf8编码而被冷冷拒绝!
所以整理utf8的编码问题,有时候还是要一直看到二进制上面来,这样问题发生在哪里也就会比较清楚,该怎样解决就不再像是霰弹枪编程,左试右试都不知道哪里出错了哟。