最近在处理文件时发现了一样类型的文件使用的编码多是不一样的。因此想将文件的格式统一一下(由于UTF-8的通用性,决定往UTF-8统一),碰见的第一个问题是:如何查看现有文件的编码方式。
上网找了一下,找到几篇比较好文章,这里就不转载啦把连接搞过来。
文件编码问题集锦
字符串编码(charset,encoding,decoding)问题原理
Java编码浅析
断定文件编码或文本流编码的方法
上面的几篇文章能够当作认识编码问题的“从入门到精通”
若是你看完了上面的文章,必定了解到了,在java中,class文件采用utf8的编码方式,JVM运行时采用utf16。Java的字符串是永远都是unicode的,采用的是UTF-16的编码方式。
想测试一下,java对UTF-8文件的读写的能力,结果发现了一个很郁闷的问题,若是经过java写的UTF-8文件,使用Java能够正确的读,可是若是用记事本将相同的内容使用UTF-8格式保存,则在使用程序读取是会从文件中多读出一个不可见字符。
测试代码以下: java
import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; public class UTF8Test { public static void main(String[] args) throws IOException { File f = new File("./utf.txt"); FileInputStream in = new FileInputStream(f); // 指定读取文件时以UTF-8的格式读取 BufferedReader br = new BufferedReader(new InputStreamReader(in, "UTF-8")); String line = br.readLine(); while(line != null) { System.out.println(line); line = br.readLine(); } } }utf.txt经过记事本建立,另存时使用指定utf-8编码,其内容为:
正常的测试结果应该是直接输出utf.txt的文本内容。但是实际上却输出了下面的内容: 测试
第一行多出了一个问号。
经过上面的几篇文章应该能够想到是Java读取BOM(Byte Order Mark)的问题,在使用UTF-8时,能够在文件的开始使用3个字节的"EF BB BF"来标识文件使用了UTF-8的编码,固然也能够不用这个3个字节。
上面的问题应该就是由于对开头3个字节的读取致使的。开始不太相信这个是JDK的Bug,后来在屡次试验后,问题依然存在,就又狗狗了一下,果真找到一个以下的Bug:
Bug ID:4508058
不过在我关掉的一些页面中记得有篇文件说这个bug只在jdk1.5及以前的版本才有,说是1.6已经解决了,从目前来看1.6只是解决了读取带有BOM文件失败的问题,仍是不能区别处理有BOM和无BOM的UTF-8编码的文件,从Bug ID:4508058里的描述能够看出,这个问题将做为一个不会修改的问题关闭,对于BOM编码的识别将由应用程序本身来处理,缘由可从另处一个bug处查看到,由于Unicode对于BOM的编码的规定可能发生变化。也就是说对于一个UTF-8的文件,应用程序须要知道这个文件有没有写BOM,而后本身决定处理BOM的方式。
在上面的while循环中可加入下面的代码,测试一下读出内容: 编码
byte[] allbytes = line.getBytes("UTF-8"); for (int i=0; i < allbytes.length; i++) { int tmp = allbytes[i]; String hexString = Integer.toHexString(tmp); // 1个byte变成16进制的,只须要2位就能够表示了,取后面两位,去掉前面的符号填充 hexString = hexString.substring(hexString.length() -2); System.out.print(hexString.toUpperCase()); System.out.print(" "); }输出结果以下:
红色部分的"EF BB BF"恰好是UTF-8文件的BOM编码,能够看出Java在读文件时没能正确处理UTF-8文件的BOM编码,将前3个字节看成文本内容来处理了。
使用连接中提供的代码能够解决碰到的乱码问题:
http://koti.mbnet.fi/akini/java/unicodereader/
修改测试代码中的输入流后: spa
BufferedReader br = new BufferedReader(new UnicodeReader(in, Charset.defaultCharset().name()));
执行,能够看到正确的结果。
将用到的测试代码及UTF-8读取乱码解决(http://koti.mbnet.fi/akini/java/unicodereader)的源码放在了附件中 .net