JAVA文件操作之默认字符集编码

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u014424628/article/details/49430783

我们知道,在一些文件操作,特别是涉及到编码的时候,很让人心烦。
为什么呢?因为编码解码不一致容易出现乱码啊。。。。。。然而很多时候我们只顾及到了编码或者只顾及到解码。所以这种情况下就只能作死的一个个的试常见的编码格式。
我举个例子你看看。下面是源码

package com.xy.file;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

import org.junit.Test;

public class Encoding {
    @Test
    public void testUTF_8() throws IOException {
        String result = "";
        String str = getClass().getResource("/").getFile().toString();
        str = System.getProperty("user.dir");
        BufferedReader br = new BufferedReader(new InputStreamReader(
                new FileInputStream(new File(str + File.separator
                        + "file/file1.txt"))));
        String temp = "";
        while ((temp = br.readLine()) != null) {
            result+=temp+"\n";
        }
        System.out.println(result);
    }
}

【注】这里有一个文件:工程目录下/file/file1.txt。编码格式为utf-8(文件编码格式信息很重要)
文件内容如下:

  计算机科学  与技术学院
abc
()()【】

我们再来看一看打印输出的结果。

  璁$畻鏈虹瀛?  涓庢妧鏈闄?
abc
()锛堬級銆愩??

果然乱了。
下面看一看解决方法
解决方法一:

while ((temp = br.readLine()) != null) {
            String s = new String(temp.getBytes(), "utf-8");
            result+=s+"\n";
}

我们仅仅修改了while循环中的语句,把每次读取的一行信息重新编码,设置成utf-8。果然成功了。但是你知道这个过程究竟是怎么进行的吗?
前面我们在包装文件对象的时候用到了InputStreamReader,构造函数中使用了只带一个参数的构造函数。查看jdk文档或者源代码可以看到,这个时候会采用jvm默认的编码格式进行编码。那么问题来了,在运行这个程序的时候你知道jvm到底采用的什么编码格式呢?并且随着具体环境的不同可能这个默认的编码格式就会改变。我们可以在eclipse上简单的模拟一下修改jvm默认编码的效果。右键项目–>properties–>Resource–>TextFileEncoding
默认的是GBK,如果你没有改过的话。这样我们改来改去,发现对输出的结果没有影响啊???你在逗我吗?不是说改变了jvm的默认编码吗?怎么结果都一样。

我们拿gbk为例子,看while循环中的语句:

String s = new String(temp.getBytes(), "utf-8");

这句代码简单明了,把原来的字符串以utf-8的形式重新编码。
话是这么说,但是你知道这条代码其实包括两部分吗?
第一:temp字符串解码为bytes数组。
第二:解码后的数组从新编码为新的字符串。
问题来了,既然涉及到了编码和解码,那么他们分别采用什么字符集进行的呢?毕竟我们只看到一个utf-8。难道都是采用utf-8?
no,由String的构造函数可知编码是采用的utf-8没错。
但是解码的话其实和上面的InputStreamReader类似,采用的是jvm默认的编码格式(这里即为GBK)。好的,有点乱对吧,下面我们好好理一理。
file1.txt【文件格式:UTF-8】–>封装的FileInputStream【编码,系统默认GBK】–>每一行对应的temp字符串【解码,系统默认GBK】–>新串s【编码,UTF-8】。没错,你发现它其实是饶了一圈又绕回来了。。。。。。。
但是不要以为这样做很好,确实很多情况下没有显现出问题出来,但是其实这是有问题的。打个比方:你把水从杯子A全部倒进另一个杯子B里面,然后再从B倒回A。你觉得最后水是一样的吗?(暂且不考虑杯子上面沾上点水)。答案是不确定的。例如当杯子A比杯子B小,这个时候没有问题,或者杯子A比杯子B大,但是水比较少,杯子B能容纳得下。但是还有这种情况啊:杯子A比杯子B大,不巧A中装的水比较多,杯子B装不下。这个时候就会有水溢出。希望这个例子类比乱码对你有所帮助。
既然有问题,那么什么才是好的解决方法呢?
看看下面更改的代码:

BufferedReader br = new BufferedReader(new InputStreamReader(
                new FileInputStream(new File(str + File.separator
                        + "file/file1.txt")),"utf-8"));

没错,在构造InputStreamReader的时候就指定了编码方式(和文件的编码方式保持了一致)。其它代码不改动。
运行看看。

  计算机科学  与技术学院
abc
()()【】

乱码消失了。
对比这两种方式,会发现第二种方式更好。因为它不会出现不必要的重复编码,解码的操作,这会导致数据丢失,从而导致乱码。
而且这种方式会不经意的提醒你:我的文件到底是什么编码格式的?这条信息非常重要!

猜你喜欢

转载自blog.csdn.net/u014424628/article/details/49430783