节点流之一:FileReader-FileWriter

1. Reader与Writer

Java提供一些字符流类,以字符为单位读写数据,专门用于处理文本文件。不能操作图片,视频等非文本文件。

常见的文本文件有如下的格式:.txt、.java、.c、.cpp、.py等

注意:.doc、.xls、.ppt这些都不是文本文件。

1.1 字符输入流:Reader

java.io.Reader抽象类是表示用于读取字符流的所有类的父类,可以读取字符信息到内存中。它定义了字符输入流的基本共性功能方法。

  • public int read(): 从输入流读取一个字符。 虽然读取了一个字符,但是会自动提升为int类型。返回该字符的Unicode编码值。如果已经到达流末尾了,则返回-1。

  • public int read(char[] cbuf): 从输入流中读取一些字符,并将它们存储到字符数组 cbuf中 。每次最多读取cbuf.length个字符。返回实际读取的字符个数。如果已经到达流末尾,没有数据可读,则返回-1。

  • public int read(char[] cbuf,int off,int len):从输入流中读取一些字符,并将它们存储到字符数组 cbuf中,从cbuf[off]开始的位置存储。每次最多读取len个字符。返回实际读取的字符个数。如果已经到达流末尾,没有数据可读,则返回-1。

  • public void close() :关闭此流并释放与此流相关联的任何系统资源。

注意:当完成流的操作时,必须调用close()方法,释放系统资源,否则会造成内存泄漏。

1.2 字符输出流:Writer

java.io.Writer抽象类是表示用于写出字符流的所有类的超类,将指定的字符信息写出到目的地。它定义了字节输出流的基本共性功能方法。

  • public void write(int c) :写出单个字符。

  • public void write(char[] cbuf):写出字符数组。

  • public void write(char[] cbuf, int off, int len):写出字符数组的某一部分。off:数组的开始索引;len:写出的字符个数。

  • public void write(String str):写出字符串。

  • public void write(String str, int off, int len) :写出字符串的某一部分。off:字符串的开始索引;len:写出的字符个数。

  • public void flush():刷新该流的缓冲。

  • public void close() :关闭此流。

注意:当完成流的操作时,必须调用close()方法,释放系统资源,否则会造成内存泄漏。

2. FileReader 与 FileWriter

2.1 FileReader

java.io.FileReader类用于读取字符文件,构造时使用系统默认的字符编码和默认字节缓冲区。

  • FileReader(File file): 创建一个新的 FileReader ,给定要读取的File对象。

  • FileReader(String fileName): 创建一个新的 FileReader ,给定要读取的文件的名称。

**举例:**读取hello.txt文件中的字符数据,并显示在控制台上

public class FileReaderWriterTest {  
      
    //实现方式1  
    @Test  
    public void test1() throws IOException {  
        //1. 创建File类的对象,对应着物理磁盘上的某个文件  
        File file = new File("hello.txt");  
        //2. 创建FileReader流对象,将File类的对象作为参数传递到FileReader的构造器中  
        FileReader fr = new FileReader(file);  
        //3. 通过相关流的方法,读取文件中的数据  
//        int data = fr.read(); //每调用一次读取一个字符  
//        while (data != -1) {  
//            System.out.print((char) data);  
//            data = fr.read();  
//        }  
        int data;  
        while ((data = fr.read()) != -1) {  
            System.out.print((char) data);  
        }  
​  
        //4. 关闭相关的流资源,避免出现内存泄漏  
        fr.close();  
​  
    }  
​  
    //实现方式2:在方式1的基础上改进,使用try-catch-finally处理异常。保证流是可以关闭的  
    @Test  
    public void test2() {  
        FileReader fr = null;  
        try {  
            //1. 创建File类的对象,对应着物理磁盘上的某个文件  
            File file = new File("hello.txt");  
            //2. 创建FileReader流对象,将File类的对象作为参数传递到FileReader的构造器中  
            fr = new FileReader(file);  
            //3. 通过相关流的方法,读取文件中的数据  
            /*  
             * read():每次从对接的文件中读取一个字符。并将此字符返回。  
             * 如果返回值为-1,则表示文件到了末尾,可以不再读取。  
             * */  
//            int data = fr.read();  
//            while(data != -1){  
//                System.out.print((char)data);  
//                data = fr.read();  
//            }  
​  
            int data;  
            while ((data = fr.read()) != -1) {  
                System.out.println((char) data);  
            }  
​  
        } catch (IOException e) {  
            e.printStackTrace();  
        } finally {  
            //4. 关闭相关的流资源,避免出现内存泄漏  
            try {  
                if (fr != null)  
                    fr.close();  
            } catch (IOException e) {  
                e.printStackTrace();  
            }  
        }  
    }  
​  
    //实现方式3:调用read(char[] cbuf),每次从文件中读取多个字符  
    @Test  
    public void test3() {  
        FileReader fr = null;  
        try {  
            //1. 创建File类的对象,对应着物理磁盘上的某个文件  
            File file = new File("hello.txt");  
            //2. 创建FileReader流对象,将File类的对象作为参数传递到FileReader的构造器中  
            fr = new FileReader(file);  
            //3. 通过相关流的方法,读取文件中的数据  
            char[] cbuf = new char[5];  
            /*  
             * read(char[] cbuf) : 每次将文件中的数据读入到cbuf数组中,并返回读入到数组中的  
             * 字符的个数。  
             * */  
            int len; //记录每次读入的字符的个数  
            while ((len = fr.read(cbuf)) != -1) {  
                //处理char[]数组即可  
                //错误:  
//                for(int i = 0;i < cbuf.length;i++){  
//                    System.out.print(cbuf[i]);  
//                }  
                //错误:  
//                String str = new String(cbuf);  
//                System.out.print(str);  
                //正确:  
//                for(int i = 0;i < len;i++){  
//                    System.out.print(cbuf[i]);  
//                }  
                //正确:  
                String str = new String(cbuf, 0, len);  
                System.out.print(str);  
            }  
        } catch (IOException e) {  
            e.printStackTrace();  
        } finally {  
            //4. 关闭相关的流资源,避免出现内存泄漏  
            try {  
                if (fr != null)  
                    fr.close();  
            } catch (IOException e) {  
                e.printStackTrace();  
            }  
        }  
    }  
}

不同实现方式的类比:

image-20220518095907714

2.2 FileWriter

java.io.FileWriter类用于写出字符到文件,构造时使用系统默认的字符编码和默认字节缓冲区。

  • FileWriter(File file): 创建一个新的 FileWriter,给定要读取的File对象。

  • FileWriter(String fileName): 创建一个新的 FileWriter,给定要读取的文件的名称。

  • FileWriter(File file,boolean append): 创建一个新的 FileWriter,指明是否在现有文件末尾追加内容。

举例:

public class FWWrite {  
    //注意:应该使用try-catch-finally处理异常。这里出于方便阅读代码,使用了throws的方式  
    @Test  
    public void test01()throws IOException {  
        // 使用文件名称创建流对象  
        FileWriter fw = new FileWriter(new File("fw.txt"));  
        // 写出数据  
        fw.write(97); // 写出第1个字符  
        fw.write('b'); // 写出第2个字符  
        fw.write('C'); // 写出第3个字符  
        fw.write(30000); // 写出第4个字符,中文编码表中30000对应一个汉字。  
          
        //关闭资源  
        fw.close();  
    }  
    //注意:应该使用try-catch-finally处理异常。这里出于方便阅读代码,使用了throws的方式  
    @Test  
    public void test02()throws IOException {  
        // 使用文件名称创建流对象  
        FileWriter fw = new FileWriter(new File("fw.txt"));  
        // 字符串转换为字节数组  
        char[] chars = "尚硅谷".toCharArray();  
​  
        // 写出字符数组  
        fw.write(chars); // 尚硅谷  
​  
        // 写出从索引1开始,2个字符。  
        fw.write(chars,1,2); // 硅谷  
​  
        // 关闭资源  
        fw.close();  
    }  
    //注意:应该使用try-catch-finally处理异常。这里出于方便阅读代码,使用了throws的方式  
    @Test  
    public void test03()throws IOException {  
        // 使用文件名称创建流对象  
        FileWriter fw = new FileWriter("fw.txt");  
        // 字符串  
        String msg = "尚硅谷";  
​  
        // 写出字符数组  
        fw.write(msg); //尚硅谷  
​  
        // 写出从索引1开始,2个字符。  
        fw.write(msg,1,2);  // 硅谷  
​  
        // 关闭资源  
        fw.close();  
    }  
      
    @Test  
    public void test04(){  
        FileWriter fw = null;  
        try {  
            //1. 创建File的对象  
            File file = new File("personinfo.txt");  
            //2. 创建FileWriter的对象,将File对象作为参数传递到FileWriter的构造器中  
            //如果输出的文件已存在,则会对现有的文件进行覆盖  
            fw = new FileWriter(file);  
//            fw = new FileWriter(file,false);  
            //如果输出的文件已存在,则会在现有的文件末尾写入数据  
//            fw = new FileWriter(file,true);  
​  
            //3. 调用相关的方法,实现数据的写出操作  
            //write(String str) / write(char[] cbuf)  
            fw.write("I love you,");  
            fw.write("you love him.");  
            fw.write("so sad".toCharArray());  
        } catch (IOException e) {  
            e.printStackTrace();  
        } finally {  
            //4. 关闭资源,避免内存泄漏  
            try {  
                if (fw != null)  
                    fw.close();  
            } catch (IOException e) {  
                throw new RuntimeException(e);  
            }  
        }  
    }  
}

2.3 小结


因为出现流资源的调用,为了避免内存泄漏,需要使用try-catch-finally处理异常


对于输入流来说,File类的对象必须在物理磁盘上存在,否则执行就会报FileNotFoundException。如果传入的是一个目录,则会报IOException异常。

对于输出流来说,File类的对象是可以不存在的。
  > 如果File类的对象不存在,则可以在输出的过程中,自动创建File类的对象
  > 如果File类的对象存在,
    > 如果调用FileWriter(File file)或FileWriter(File file,false),输出时会新建File文件覆盖已有的文件
    > 如果调用FileWriter(File file,true)构造器,则在现有的文件末尾追加写出内容。

3. 关于flush(刷新)

因为内置缓冲区的原因,如果FileWriter不关闭输出流,无法写出字符到文件中。但是关闭的流对象,是无法继续写出数据的。如果我们既想写出数据,又想继续使用流,就需要flush() 方法了。

  • flush() :刷新缓冲区,流对象可以继续使用。

  • close():先刷新缓冲区,然后通知系统释放资源。流对象不可以再被使用了。

注意:即便是flush()方法写出了数据,操作的最后还是要调用close方法,释放系统资源。

举例:

public class FWWriteFlush {  
    //注意:应该使用try-catch-finally处理异常。这里出于方便阅读代码,使用了throws的方式  
    @Test  
    public void test() throws IOException {  
        // 使用文件名称创建流对象  
        FileWriter fw = new FileWriter("fw.txt");  
        // 写出数据,通过flush  
        fw.write('刷'); // 写出第1个字符  
        fw.flush();  
        fw.write('新'); // 继续写出第2个字符,写出成功  
        fw.flush();  
​  
        // 写出数据,通过close  
        fw.write('关'); // 写出第1个字符  
        fw.close();  
        fw.write('闭'); // 继续写出第2个字符,【报错】java.io.IOException: Stream closed  
        fw.close();  
    }  
}
Java基础

IO流原理及流的分类

2025-8-19 15:00:00

Java基础

节点流之二:FileInputStream-FileOutputStream

2025-8-21 15:00:00

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
今日签到
有新私信 私信列表
搜索