background image

Java

 

编码问题汇总

工作中经常遇到 java 编码问题,由于缺乏研究,总是无法给出确切的答案,这个周末在
网上查了一些资料,在此做些汇总。

    问题一:在 java 中读取文件时应该采用什么编码?

Java 读取文件的方式总体可以分为两类:按字节读取和按字符读取。按字节读取就是采用
InputStream.read()方法来读取字节,然后保存到一个 byte[] 数组中,最后经常用 new 
String(byte[]); 把 字 节 数 组 转 换 成 String 。 在 最 后 一 步 隐 藏 了 一 个 编 码 的 细 节 , new 
String(byte[]);会使用操作系统默认的字符集来解码字节数组,中文操作系统就是 GBK。而
我们从输入流里读取的字节很可能就不是 GBK 编码的,因为从输入流里读取的字节编码
取决于被读取的文件自身的编码。举个例子:我们在 D:盘新建一个名为 demo.txt 的文件,

写入 我们。 ,并保存。此时 demo.txt 编码是 ANSI,中文操作系统下就是 GBK。此时我们
用输入字节流读取该文件所得到的字节就是使用 GBK 方式编码的字节。那么我们最终
new String(byte[]);时采用平台默认的 GBK 来编码成 String 也是没有问题的(字节编码和默
认解码一致)。试想一下,如果在保存 demo.txt 文件时,我们选择 UTF-8 编码,那么该文
件的编码就不在是 ANSI 了,而变成了 UTF-8。仍然采用输入字节流来读取,那么此时读
取的字节和上一次就不一样了,这次的字节是 UTF-8 编码的字节。两次的字节显然不一样,
一个很明显的区别就是:GBK 每个汉字两个字节,而 UTF-8 每个汉字三个字节。如何我
们最后还使用 new String(byte[]);来构造 String 对象,则会出现乱码,原因很简单,因为构
造时采用的默认解码 GBK,而我们的字节是 UTF-8 字节。正确的办法就是使用 new 
String(byte[],”UTF-8”);来构造 String 对象。此时我们的字节编码和构造使用的解码是一致
的,不会出现乱码问题了。

 

说完字节输入流,再来说说字节输出流。

我们知道如果采用字节输出流把字节输出到某个文件,我们是无法指定生成文件的编码
的(假设文件以前不存在),那么生成的文件是什么编码的呢?经过测试发现,其实这取
决于写入的字节编码格式。比如以下代码:

OutputStream out = new FileOutputStream("d:\\demo.txt");

out.write("我们".getBytes());

getBytes()会采用操作系统默认的字符集来编码字节,这里就是 GBK,所以我们写入
demo.txt 文件的是 GBK 编码的字节。那么这个文件的编码就是 GBK。如果稍微修改一下程
序 : out.write(" 我 们 ".getBytes(“UTF-8”)); 此 时 我 们 写 入 的 字 节 就 是 UTF-8 的 , 那 么
demo.txt 文件编码就是 UTF-8

。这里还有一点,如果把 我们 换成 123 或 abc 之类的 ascii

码字符,那么无论是采用 getBytes()或者 getBytes(“UTF-8”)那么生成的文件都将是 GBK 编
码的。