再谈java乱码:GBK和UTF-8互转尾部乱码问题分析
来源:互联网 发布:淘宝网汽车座套 编辑:程序博客网 时间:2024/06/01 17:48
一直以为,Java中任意unicode字符串,可以使用任意字符集转为byte[]再转回来,只要不抛出异常就不会丢失数据,事实证明这是错的。
经过这个实例,也明白了为什么 getBytes()需要捕获异常,虽然有时候它也没有捕获到异常。
言归正传,先看一个实例。
用ISO-8859-1中转UTF-8数据
设想一个场景:
用户A,有一个UTF-8编码的字节流,通过一个接口传递给用户B;
用户B并不知道是什么字符集,他用ISO-8859-1来接收,保存;
在一定的处理流程处理后,把这个字节流交给用户C或者交还给用户A,他们都知道这是UTF-8,他们解码得到的数据,不会丢失。
下面代码验证:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
输出:
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
用GBK中转UTF-8数据
重复前面的流程,将ISO-8859-1 用GBK替换。
只把中间一段改掉:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 1
- 2
- 3
- 4
- 5
- 6
- 7
运行结果:
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
好像没有问题,这就是一个误区。
修改原文字符串重新测试
将两个汉字 “用户” 修改为三个汉字 “用户名” 重新测试。
ISO-8859-1测试结果:
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
GBK 测试结果:
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
结论出来了
ISO-8859-1 可以作为中间编码,不会导致数据丢失;
GBK 如果汉字数量为偶数,不会丢失数据,如果汉字数量为奇数,必定会丢失数据。
why?
为什么奇数个汉字GBK会出错
直接对比两种字符集和奇偶字数的情形
重新封装一下前面的逻辑,写一段代码来分析:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
输出结果:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
为什么GBK会出错
前三段都没问题,最后一段,奇数个汉字的utf-8字节流转成GBK字符串,再转回来,前面一切正常,最后一个字节,变成了 “0x3f”,即”?”
我们使用”用户名” 三个字来分析,它的UTF-8 的字节流为:
[e7 94 a8] [e6 88 b7] [e5 90 8d]
我们按照三个字节一组分组,他被用户A当做一个整体交给用户B。
用户B由于不知道是什么字符集,他当做GBK处理,因为GBK是双字节编码,如下按照两两一组进行分组:
[e7 94] [a8 e6] [88 b7] [e5 90] [8d ?]
不够了,怎么办?它把 0x8d当做一个未知字符,用一个半角Ascii字符的 “?” 代替,变成了:
[e7 94] [a8 e6] [88 b7] [e5 90] 3f
数据被破坏了。
为什么 ISO-8859-1 没问题
因为 ISO-8859-1 是单字节编码,因此它的分组方案是:
[e7] [94] [a8] [e6] [88] [b7] [e5] [90] [8d]
因此中间不做任何操作,交回个用户A的时候,数据没有变化。
关于Unicode编码
因为UTF-16 区分大小端,严格讲:unicode==UTF16LE。
- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 3
- 4
- 5
- 6
运行结果:
- 1
- 2
- 3
- 1
- 2
- 3
其中 “fe ff” 为小端消息头,同理,大端消息头为 “ff fe”。
小结
作为中间转存方案,ISO-8859-1 是安全的。
UTF-8 字节流,用GBK字符集中转是不安全的;反过来也是同样的道理。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
getBytes() 是会丢失数据的操作,而且不一定会抛异常。
unicode是安全的,因为他是java使用的标准类型,跨平台无差异。
- 再谈java乱码:GBK和UTF-8互转尾部乱码问题分析
- 再谈java乱码:GBK和UTF-8互转尾部乱码问题分析
- 再谈java乱码:GBK和UTF-8互转尾部乱码问题分析
- 再谈java乱码:GBK和UTF-8互转尾部乱码问题分析
- 再谈java乱码:GBK和UTF-8互转尾部乱码问题分析
- 再谈java乱码:GBK和UTF-8互转尾部乱码问题分析
- GBK和UTF-8互转尾部乱码问题分析
- java乱码问题解决:GBK和UTF-8互转尾部乱码问题分析
- java乱码:GBK和UTF-8互转尾部乱码问题分析
- 再再谈java乱码:GBK和UTF-8互转尾部乱码问题分析(续)
- java gbk转utf-8乱码问题
- java gbk转utf-8乱码问题
- java gbk转utf-8乱码问题
- 解决UTF-8和GBK之间转换乱码问题
- 解决utf-8和GBK中文乱码问题
- java gbk--utf-8乱码解决函数
- HttpURLConnection以及GBK转UTF-8中文部分乱码问题
- Python 处理GBK编码转UTF-8读写乱码问题
- 乱谈Qt事件循环嵌套
- 多线程 ThreadGroup activeCount没有作用的情况下,多线程也可以自己写,ThreadGroup不一定好使
- 为什么时间越紧,越容易拖延?--致拖延症患者
- Java设计模式--代理模式【Proxy Pattern】
- ajax访问jeesite session超时时返回 json
- 再谈java乱码:GBK和UTF-8互转尾部乱码问题分析
- mysql视图的作用(详细)
- 【Java】String经MD5加密后的32位输出
- Integer类型与int的==比较
- 关于获取图片在网页加载后的高度
- javascript – 为什么null是一个对象,null和undefined之间有什么区别?(最通俗的解释,推荐)
- java mail发送邮件
- 架构师的能力模型
- Python 安装