黑马程序员_I/O流(字符编码问题)

来源:互联网 发布:js获取标签所有属性 编辑:程序博客网 时间:2024/06/05 23:19
---------- android培训、java培训、java学习型技术博客,期待与您交流!----------
        字符编码问题是程序开发中经常遇到的问题,造成的原因其实并不复杂,但需要注意避免和解决。
        先来回顾下在转换流中有所涉及过的字符编码。
import java.io.*;class EncodeStream{public static void main(String[] args) throws IOException {//writeText();readText();}public static void readText() throws IOException {InputStreamReader isr = new InputStreamReader(new FileInputStream("utf.txt"),"UTF-8");char[] buf = new char[10];int len = isr.read(buf);String str = new String(buf,0,len);System.out.println(str);isr.close();}public static void writeText() throws IOException {OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("utf.txt"),"UTF-8");osw.write("你好");osw.close();}}

        首先可以明确的是在平台下,中文默认是GBK编码,因此,无论是否指定编码要求为“GBK”,“你好”都会编码成4字节长的文件,而用UTF-8编码时,同样的“你好”文件就变成了6字节。如果以GBK编码写入却以UTF-8编码读取,会读取不出内容,反之则会读取出与原数据不相符的内容。这是由GBK编码用两个字节来表示中文而UTF-8编码用三个字节来表示中文造成的。
        参考上面的代码来概述一下编码解码原理和代码实现。编码就是字符串变成字节数组,解码就是字节数组变成字符串。String -->byte[ ]使用str.getBytes(charsetName),而byte[ ] -->String使用new String(byte[ ],charsetName)。示例代码如下:
import java.util.*;class EncodeDemo{public static void main(String[] args) throws Exception {String s = "你好";byte[] b1 = s.getBytes("GBK");System.out.println(Arrays.toString(b1));String s1 = new String(b1,"ISO8859-1");System.out.println("s1="+s1);//对s1进行ISO8859-1编码byte[] b2 = s1.getBytes("ISO8859-1");System.out.println(Arrays.toString(b2));String s2 = new String(b2,"GBK");System.out.println("s2="+s2);}}

        在上面的代码中,演示了如何在解码错误的情况下重新获取正确的数据。但是需要注意的是,如果编码时使用GBK编码表,解码时错误的使用了UTF-8的编码表,则原字节数组是无法这样还原的。究其原因,ISO8859-1编码表中没有中文编码,而UTF-8中是包含中文编码的,因此将GBK编码的字节数组用UTF-8错误的解码之后,再用UTF-8重新编码取不回原先的字节数组。
        最后看一个有趣的编码现象,也就可以理解UTF-8的编码判断了。新建一个文本文件,只输入“联通”,保存后关闭。再次打开该文件,会发现原本的内容“联通”变成了乱码。应用下面的代码,观察“联通”在GBK编码后的二进制字节数据就能看出端倪:
class EncodeDemo2{public static void main(String[] args) throws Exception {String s = "联通";byte[] by = s.getBytes("GBK");for(byte b : by){System.out.println(Integer.toBinaryString(b&255));}}}

        原来,“联通”在被GBK编码后变成了:11000001,10101010,11001101,10101000。查询UTF-8的编码格式表后就能看出,原来其正好符合UTF-8编码表的格式规范。因此,明明是以GBK编码的“联通”在解码时被错误的识别为了UTF-8编码,所以也就无法正常显示原始数据了。
---------- android培训、java培训、java学习型技术博客,期待与您交流!----------