Java – IO流 – FileReader字符输入流

简介

操作本地文件的字符输入流,可以把本地文件中的文本数据读取到程序中来。

 

创建输入流

1.创建字符输入流对象

2.读数据

3.释放资源

 

创建对象

// 以字符串形式表达文件目录位置
public FileReader(String name);

// 以File 对象的形式表达文件目录位置
public FileReader(File name);

// JDK11 之后新增的数据转换流方式,允许通过自定义字符集的方式解码文件
public FileReader(File name, Charset charName);

注意:如果文件不存在或路径不正确,会直接报错异常。

 

读取数据

// 读取一个字符的数据,返回 int 型,以ASCII码转出,每调用一次就读取一个字符
// ,如果已经读到文件尾,会返回 -1
public int read();

// 一次读取多个字符的数据,返回 int 型,返回的数据为读取的数据长度,
// 读取的多个字符数据会存到一个字符数组中,一次读取多少字符,全看这个 char[] 数组声明
// 了多少个成员
// 每一次的read 读取中,都会尽可能的覆盖填满 char[] 字节数组,但如果到了文件
// 末尾时,数据存不满,那么上一次填充的数据中,有可能依然还在,因此要注意最后
// 一次读取时的数据处理。
public int read(char[] buffc); 

注意:FileReader 的 read 和 FileInputStream 有所不同,FileReader 的 read 当遇到中文字时,会把整个中文字读取,而FileInputStream 的 read 依然只会读取一个字节。

 

FileReader循环读取

FileReader fr = new FileReader("Learn\\src\\a.txt");
int c;
// 循环读取一个字,不管它是占1字节还是2字节,会自动读取
while ((c = fr.read()) != -1) {
    System.out.println((char) c);
}

 

释放资源

Java在读文件的时候,会对文件进行占用锁定,期间其它程序无法对它进行操作,因此我们对文件操作完成后,应该要对文件进行解锁去除占用。

fr.close();

 

异常中的处理(普通方式)

FileReader 中,包含了编译时异常,如果调用FileReader 创建构造时,会出现编译错误,需要我们 throws 抛出异常。

同时也可以使用 try...catch  的方式进行处理。

但是 try...catch  中存在两个问题:

问题一: FileReader 找不到文件时会直接抛出异常,try 中一旦出现异常时,会停止执行 try 下面的代码,这使得 close()  关闭流这种方法有可能没有执行到。

try {
            // 如果 FileReader  出现异常,后面的代码不会执行
            FileReader fr = new FileReader ("不存在的文件");
            // 这里的代码不会被执行,所以 fr.close() 也不会被执行
            fr.close();
        }catch (IOException e){
            e.printStackTrace();
        }finally {
            // 如果把 fr.close() 放在这里,则因为作用域的原因,会找不到 fr 对象
            fr.close();
        }

解决方法是,把 FileReader    创建对象移出 try 作用域外

 

// 把 FileReader  创建对象移出作用域名,必须初始化为 null,否则 finally 处的 fr.close 会报编译错误
// 原因是,未初始化的对象不能调用 任何 方法
        FileReader fr = null;
        try {
            // 但因 FileReader 本身也有编译异常,所以不能在 try 外面 new 
            fr = new FileReader("不存在的文件");
            // 这里的代码不会被执行,所以 fr.close() 也不会被执行
            fr.close();
        }catch (IOException e){
            e.printStackTrace();
        }finally {
            // 如果把 fr.close() 放在这里,则因为作用域的原因,会找不到 fr 对象
            fr.close();
        }

 

问题二:假如,try 中的 FileReader 创建依然报错,那么 fr 对象依然是null ,这时调用 finally 代码块中的 fr.close()  时,依然会报错

// 把 FileReader 创建对象移出作用域名
        FileReader  fr = null;
        try {
            // 但因 FileReader 本身也有编译异常,所以不能在 try 外面 new
            fr = new FileReader("不存在的文件");
            // 这里的代码不会被执行,所以 fr.close() 也不会被执行
            fr.close();
        }catch (IOException e){
            e.printStackTrace();
        }finally {
            if (fr != null){
                fr.close();
            }
        }

解决方法是:在 调用 close()  方法之前,判断 fr 是否为 null

 

异常中的处理(JDK7方式)

Java 也发现了普通方法中处理 close() 是比较麻烦的,所以在JDK 7 后,提供一个自动关闭文件接口 AutoCloseable 方法,FileReader 实现了 AutoCloseable 接口,我们不需要手动去调用 close()  方法

用法如下

try(定义字节流1; 定义字节流2) {
            fr... 处理逻辑
            fr2... 处理逻辑
}catch (IOException e){
            
}

在JDK7中,try 多出一个小括号,括号中编写定义字节流的方法,多个字节流定义,使用; 进行分割即可。

try(FileReader fr = new FileReader("不存在的路径");
     FileReader  fr2 = new FileReader("不存在的路径")) {
            fis... 处理逻辑
            fis2... 处理逻辑
}catch (IOException e){
            
}

不需要调用 close()  方法

 

异常中的处理(JDK9方式)

从JDK7的方案来看,确实比较好,但是在 try()  中传入创建方法,使得代码非常长,不利于阅读,在JDK9 中,Java 允许创建方法在try()  代码块外面定义,try() 中传个对象即可。

FileReader  fr = new FileReader ("不存在的路径");
FileReader Stream fr2 = new FileReader ("不存在的路径");
try(fr; fr2) {
            fr... 处理逻辑
            fr2... 处理逻辑
}catch (IOException e){
            
}

多个对象,依然使用 ; 分割即可。

 

FileReader底层原理

1.当创建FileReader对象时,对象内部会生成一个 byte[8192] 的数组。

2.当调用第一次 read() 方法时,FileReader 会读取文件,并尽量填满数组中的 8192 个成员

3.当 read() 发现成员为 负数 时,说明读取到非英文字(或中文),read() 会根据字符集的规则,连续读取对应字节数(2~4字节,中文为3字节),并转为整型数字

4.在空参 read() 方法中,会直接把整型数字输出,如果是非空参 read(char[] buffc) 方法中,会存入用户事先提供的数组,并输出读取字节长度。

5.当 read() 方法已完成读取 byte[8192] 个成员后,再次读取文件中的数据,以次以尽可能的方式填满数组。

6.当第二次读取文件时,新的数据会覆盖数组成员,但如果第二次读取的数据没有填满 byte[8192] 个成员,则剩下的成员依然保留上一次读取的数据(即每一次读取文本不会清空数组)。

注意:FileInputStream 中的 read() 不具有 byte[] 数据缓冲机制。

 

示例:读取txt文件

FileReader fr = new FileReader("path");
    int len;
    // 定义字符数组,每次读取10个字出来
    char[] c = new char[10];
    while ((len = fr.read(c)) != -1) {
       System.out.print(new String(c, 0, len));
}

 

 

如果您喜欢本站,点击这儿不花一分钱捐赠本站

这些信息可能会帮助到你: 下载帮助 | 报毒说明 | 进站必看

修改版本安卓软件,加群提示为修改者自留,非本站信息,注意鉴别

THE END
分享
二维码
打赏
海报
Java – IO流 – FileReader字符输入流
简介 操作本地文件的字符输入流,可以把本地文件中的文本数据读取到程序中来。   创建输入流 1.创建字符输入流对象 2.读数据 3.释放资源   创建对象 // 以字符串形式表达文件目录位……
<<上一篇
下一篇>>