乱码问题经常碰到,而且每次都要花很久时间才能解决。最近想搞清楚一些实质性的东西,看了一些关于这方面的资料,在这里做个记录
造成字符乱码问题的原因有两个:
1是编码很解码的方式不一致,
2是采用了错误的编码造成数据丢失。
由于计算机的最小存储单元是字节即8位二进制数,中文是无法在内存中直接表示的,所以从字符到字节就需要通过某个规则转换即编码
编码方式有很多 我比较常用的是utf-8 GBK iso-8859-1和ASCII,这些都可以看成是字典表。
比如我用utf-8的方式去编码字符串"你好"
String str = "你好";
byte[] utf8 = str.getBytes("utf-8");
for(byte b : utf8){
System.out.print(" "+b);
}
输出的结果是: -28 -67 -96 -27 -91 -67
说明“你好”这个字符串被编码成了 6个字节,utf-8是用三个字节表示一个中文字符的,这种转换过程相当于我们查字典
如果用GBK编码
String str = "你好";
byte[] gbk = str.getBytes("GBK");
for(byte b : gbk){
System.out.print(" "+b);
}
得到的结果是: -60 -29 -70 -61 GBK是用两个字节表示一个中文字符的(需要注意getBytes()这个方法有两种形式 一个是带参数一个不带参数,
不带参用系统默认编码,中文windows操作系统一般都是GBK 一种查看系统编码的方式是用命令行chcp 936表示GBK)
到这里我们就可以解释我们的第一个原因
比如我们用从网络中去抓取数据的时候,对方用GBK方式进行编码,我们拿到字节流的时候用utf-8进行解码,
百度用的是GBK编码
URL url = new URL("http://www.baidu.com/");
URLConnection connection = url.openConnection();
InputStream inputStream = connection.getInputStream();
InputStreamReader reader = new InputStreamReader(inputStream, "utf-8");
BufferedReader bufferedReader = new BufferedReader(reader);
System.out.println("bufferedReader = " + bufferedReader.readLine());
得到的结果是:
bufferedReader = <!doctype html><html><head><meta http-equiv="Content-Type" content="text/html;charset=gb2312"><title>????????????? 。。。。
如果是GBK解码字节流得到如下的结果
<!doctype html><html><head><meta http-equiv="Content-Type" content="text/html;charset=gb2312"><title>百度一下,你就知道 。。。。
由于编解码方式不一致,utf8去解码字节流的时候从“字典”中查不到相应的字符,
默认(有几种 “?"也是我们经常见到的一种)用U+003F代替 即 “?”
这里有个问题我还没有搞清楚,我用GBK编码”你好“再用utf-8解码得到的是3个”?“ 为什么是3个"?"
如果了解utf-8 GBK和iso-8859-1等这些的具体编码方式,第二个问题就比较清楚了。
比如iso-8859-1是单字节编码的,比起ASSCII,iso-8859-1把一个字节的最高位也纳入进来表示字符,但是最多也只有256个字符,
实际上它是在ASSCII基础之上加入了一些西欧字符,并没有加入中文,所以iso-8859-1也不能表示中文,如果我们这么写
String str = "你好";
byte[] bytes = str.getBytes("iso-8859-1");
System.out.println("bytes = " + new String(bytes,"utf-8")); /////输出 ??
System.out.println("bytes = " + new String(bytes,"GBK")); /////输出 ??
System.out.println("bytes = " + new String(bytes,"iso-8859-1")); /////输出 ??
由于在“字典”中找不到相应的值,就用3f替代 我们用上面的方式打印 得到的都会是"??",
java用的是Unicode编码,API中Character类下有描述:“字符信息基于 Unicode 标准,版本 4.0。。。”
更实际的Web编程中遇到的浏览器显示乱码和应用程序接收提交过去的乱码问题以下博客中都有详细的描述,