java的编码原理

来源:互联网 发布:淘宝无线端装修工具 编辑:程序博客网 时间:2024/04/29 17:22

场景:右键新建一个记事本文件,输入 “我学ABC”。保存,编码选择为ACSI。


那么,从输入法到最后存储硬盘是怎样的过程呢?

首先,新建文本会有默认操作系统的编码方式,中文一般是GBK。然后输入字符到记事本程序,字符被转换为按GBK编码(通俗讲就是对照编码表,这些每个字符对应的编码)存储到硬盘上,如果按acsi码编码存储的话,GBK可以用ascii存,2字节。


下图16进制显示,文本大小是7个字节,当然存储硬盘的是二进制。



好,如果再次打开该文件,当然也是一个同样的解码过程。记事本是怎样知道该文件是GBK的呢?下边会提到。


现在,我们用记事本打开刚才的文件,右击另存为,选择编码UTF-8保存覆盖。那么此时存储在硬盘上的什么样的数据呢?

一共12个字节。BOM是文件头,标识编码方式是UTF-8。刚才的GBK其实是记事本程序靠猜的。



如果我们用java读取文件并显示打印出来,这是个怎样的过程?

try {     File f = new File("E:\\aaa.txt");                          if(f.isFile() && f.exists()){ //判断文件是否存在                 InputStreamReader read = new InputStreamReader(new FileInputStream(f),"GBK");//按gbk读取到并翻译成字符,utf-16存储在内存                 BufferedReader bufferedReader = new BufferedReader(read);                 String lineTxt = null;                                  while((lineTxt = bufferedReader.readLine()) != null){                 System.out.println(lineTxt);                 byte[] line=lineTxt.getBytes("GBK");//字符按GBK翻译成字节                 for(byte b:line){                 String hex=Integer.toHexString(b);                 System.out.print(hex.substring(hex.length()-2,hex.length())+" ");                 }                 }                 read.close();     }     } catch (Exception e) {         System.out.println("读取文件内容出错");         e.printStackTrace();    }

这里aaa.txt是个按GBK编码的文件,“我学ABC”。

InputStreamReader read = new InputStreamReader(new FileInputStream(f),"GBK");
<pre name="code" class="java">lineTxt = bufferedReader.readLine())

按照正常逻辑,从文件流读取到bit数组,然后用GBK解码,形成字符串  “我学ABC”,并且按照utf-16方式存在内存里,变量类型是String。java一个char是2个字节。

byte[] line=lineTxt.getBytes("GBK");//字符按GBK翻译成字节
然后再重新按GBK进行编码,转回到字节数组,并打印出上边的第一张图。UTF-8也是如此。


这好像都没什么问题,到现在。


如果我们平时编写代码不注意情况下,比如,刚才的GBK文件用UTF-8去取,或者采用默认编码去读,会发生什么?

InputStreamReader read = new InputStreamReader(new FileInputStream(f),"UTF-8");

很遗憾,显示乱码。因为我们用UTF-8方式去解码一串 ce d2 d1 a7 41 42 43这样的二进制数据,ce d2 d1 a7 是显示异常字符,而ABC是asici范围,不受影响。

而下边打印出来的ef bf bd ef bf bd d1 a7是什么呢,有2个ef bf bd,原来它是��ѧABC字符对应的UTF-8的解码字节。



有些人还试图还原回来,其实此时不可能了。它已经已��ѧABC的utf-16方式存在内存里了。



是不是用错的了编码方式都不能还原呢?

iso-5589-1方式读取字节,这种编码方式是单字节的,正好每个字节都能对应一个字符。

如果直接把lineTxt输出,那是乱码ÎÒѧABC。看到了吧,7个字符,正好匹配第一张图的7个字节。

把字节数组用GBK方式编码,即可显示正确的字符串。




0 0