目录
文件编码和字符串编码是我们最常听到的两个概念。
比如我们的.java文件我们需要设置文件编码,不然可能不能正常在ide里头打开。再比如字符串编码,字符串编码经常会涉及到乱码问题。
如下:

上图只是简单的罗列了一个读取文件到内存中的流程。但是却涉及到了比较多的知识点在里头。

文件编码取决于保存文件时候设置的编码格式,比如我们使用notepad++创建一个a.txt文件,往里头写入“我爱中国”四个汉字,并且保存a.txt文件,此时a.txt的文件的编码取决于当前的操作系统类型:中文操作系统下就是GBK编码,那么此时a.txt里头的内容的编码就是GBK了。当然我们也可以指定编码类型保存,比如指定编码为UTF-8,那么此时a.txt里头的内容编码就是UTF-8。

为什么会引入字符串编码这么一个概念呢。是这样的,读取文件,我们通常会以流的形式读取文件,然后读取文件又分成以字符读取和以字节读取。
按字节读取就是采用InputStream.read()方法来读取字节,然后保存到一个byte[]数组中,最后经常用new String(byte[]);把字节数组转换成String。在最后一步隐藏了一个编码的细节,new String(byte[]);会使用操作系统默认的字符集来解码字节数组,中文操作系统就是GBK。而我们从输入流里读取的字节很可能就不是GBK编码的,因为从输入流里读取的字节编码取决于被读取的文件自身的编码。

分析2.2.1会发现,乱码出现的原因是new String(bytes)这个环节,没有严格保持编码,导致字节数组转成字符串可能会丢失原始编码而乱码。因此采用new String(bytes, 原始编码)即可解决。
首先,我们需要理解一下字符流。其实字符流可以看做是一种包装流,它的底层还是采用字节流来读取字节,然后它使用指定的编码方式将读取字节解码为字符。说起字符流,不得不提的就是InputStreamReader。以下是java api对它的说明: InputStreamReader是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,否则可能接受平台默认的字符集。说到这里其实很明白了,InputStreamReader在底层还是采用字节流来读取字节,读取字节后它需要一个编码格式来解码读取的字节,如果我们在构造InputStreamReader没有传入编码方式,那么会采用操作系统默认的GBK来解码读取的字节。假设demo.txt编码方式为GBK,我们使用如下代码来读取文件:
InputStreamReader in = new InputStreamReader(new FileInputStream(“demo.txt”));
那么我们读取不会产生乱码,因为文件采用GBK编码,所以读出的字节也是GBK编码的,而InputStreamReader默认采用解码也是GBK。如果把demo.txt编码方式换成UTF-8,那么我们采用这种方式读取就会产生乱码。这是因为字节编码(UTF-8)和我们的解码编码(GBK)造成的。解决办法如下:
InputStreamReader in = new InputStreamReader(new FileInputStream(“demo.txt”),”UTF-8”);
下一篇讲解下java编译文件编码。