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对象。此时我们的字节编码和构造使用的解码是一致的,不会出现乱码问题了。