io读文件显示在控制台问题汇总

今天回顾并手写了一个读文件并显示在控制台上的代码,如下:


import java.io.*;

public class ioTest {

        public static void main(String[] args){
            String path = "G:/javaworkspace/Test/io/src/";
            File file = new File(path + "test.txt");
            InputStream inputStream = null;
            int i=0;
            try {
                inputStream = new FileInputStream(file);
                byte[] bytes = new byte[16];
                while ((i = inputStream.read(bytes))!=-1){
                    String str = new String(bytes);
                    System.out.print(str);
                }
            }catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
}

test.txt文件原内容如下(随机内容,以UTF-8保存):
test内容
一,首先想到比较一下read()和read(byte[] b)的区别
根据api帮助文档加上些许个人理解,
read()从输入流中读取数据的下一个字节,返回0到255范围内的int字节值。如果因为已经到达流末尾而没有可用的字节,则返回-1。在输入数据可用、检测到流末尾或者抛出异常前,此方法一直阻塞。
read(byte[] b)从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。以整数形式返回实际读取的字节数。在输入数据可用、检测到文件末尾或者抛出异常前,此方法一直阻塞。如果 b 的长度为 0,则不读取任何字节并返回 0;否则,尝试读取至少一个字节。如果因为流位于文件末尾而没有可用的字节,则返回值 -1;否则,至少读取一个字节并将其存储在 b 中。将读取的第一个字节存储在元素 b[0] 中,下一个存储在 b[1] 中,依次类推。读取的字节数最多等于 b 的长度。
读取文档如果用read()来写的话,需要每个字节强转为相应char类型,但是读取出来的汉字肯定就是乱码了,因为char只能一个字节一个字节读,读取英文还是可以的。

二,问题1,出现全部乱码
1.上面代码运行结果如图:
运行结果1
这是因为在java中,class文件采用utf8的编码方式,JVM运行时采用utf16。Java的字符串是永远都是unicode的,采用的是UTF-16的编码方式,我理解,也就是所谓的解错码
要解决这一问题需要使用外部资源采用的字符集来读取外部数据,改进代码如下:


import java.io.*;

public class ioTest2 {
    public static void main(String[] args) {
        String path = "G:/javaworkspace/Test/io/src/";
        File file = new File(path + "test.txt");
        InputStream in = null;
        String line;
        StringBuffer sb = new StringBuffer();
        try {
            in = new FileInputStream(file);

            Reader reader = new InputStreamReader(in, "UTF-8");
            //创建使用指定字符集的 InputStreamReader
            //增加缓冲功能,提高效率
            BufferedReader br = new BufferedReader(reader);
            while ((line = br.readLine()) != null) {
                sb.append(line);
            }
            if (br != null) {
                br.close();
            }
            String content = sb.toString();
            System.out.print(content);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }       
    }

}

主要起作用的是Reader reader = new InputStreamReader(inputStream, “UTF-8”);
这一句使用外部资源的字符集也就是UTF-8来进行读文件,从而能够以正确方式转化。

三,问题2,控制台输出出现首字符问号的问题
上面代码运行结果如下:
首字符为问号
对于这一点我十分疑惑,花费了很长时间在网上查找资料,最终这篇博客对我帮助很大,而且这篇博客写的非常充实、资料也很丰富,对于解决乱码问题有很好的帮助:
解决乱码问题的博客
从这篇博客得知,这是因为文本BOM(Byte Order Mark)的机制,带有BOM的UTF-8文本首三个字节为EF BB BF ,而JDK一直存在一个BUG,那就是无法识别前三个字节把他们也当作文本内容读取了,该BUG为:
Bug ID:4508058
可以从描述看出,这个问题将作为一个不会修改的问题关闭,对于BOM编码的识别将由应用程序自己来处理,原因可从另处一个bug处查看到,因为Unicode对于BOM的编码的规定可能发生变化。也就是说对于一个UTF-8的文件,应用程序需要知道这个文件有没有写BOM,然后自己决定处理BOM的方式。
我将test.txt文件用Editplus打开,用十六进制查看器看到:
这里写图片描述
首三个字节的确是EF BB BF。
我将test.txt文件用去掉BOM的UTF-8保存,并用十六进制查看器看到:
这里写图片描述
的确是去掉了首三个字节。
运行结果如下:
这里写图片描述
经过千辛万苦,终于去掉了所有乱码,但是我这只是修改了我文件的保存方式,这篇博客中也提到了对于带BOM的文件解决办法:
http://koti.mbnet.fi/akini/java/unicodereader/

在这里我也附上里面所提到的解决乱码问题非常好的几篇文章,亲测的确很有帮助:
文件编码问题集锦
字符串编码(charset,encoding,decoding)问题原理
Java编码浅析
判定文件编码或文本流编码的方法

四,问题3,回车换行没有读出来
细心的小伙伴们都发现了,控制台上显示出来的跟文件相比,回车换行并没有读出来,这个问题我也找到了解决办法,通过 commons-io-*.jar 。
代码如下:

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.List;

import org.apache.commons.io.FileUtils;

public class commonsIOTest{
    public static void main(String[] args) {
        String path = "G:/javaworkspace/Test/io/src/";
        File file = new File(path + "test.txt");
        try {
            //方法1
            String content = FileUtils.readFileToString(file,"UTF-8");
            System.out.println(content);

            //方法2
            List<String> contents = FileUtils.readLines(file,"UTF-8");
            for (String string : contents) {
                System.out.println(string);
            }           
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }catch (IOException e) {
            e.printStackTrace();
        }

    }

}

运行结果:
这里写图片描述

Apache 的io工具包非常简便,好用,可以直接解决换行没读的问题,但是我测试了一下,首字符为问号的问题依然没有解决。

Apache的io工具包使用简例

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值