【Java】—— File类与IO流:FileReader\FileWriter、FileInputStream\FileOutputStream

目录

2. IO流原理及流的分类

2.1 Java IO原理

2.2 流的分类

2.3 流的API

3. 节点流之一:FileReader\FileWriter

3.1 Reader与Writer

3.1.1 字符输入流:Reader

3.1.2 字符输出流:Writer

3.2 FileReader 与 FileWriter

3.2.1 FileReader

3.2.2 FileWriter

3.2.3 小结

4. 节点流之二:FileInputStream\FileOutputStream

4.1 InputStream和OutputStream

4.1.1 字节输入流:InputStream

4.1.2 字节输出流:OutputStream

4.2 FileInputStream 与 FileOutputStream

4.2.1 FileInputStream

4.2.2 FileOutputStream


2. IO流原理及流的分类

2.1 Java IO原理

  • Java程序中,对于数据的输入/输出操作以“流(stream)” 的方式进行,可以看做是一种数据的流动。

  • I/O流中的I/O是Input/Output的缩写, I/O技术是非常实用的技术,用于处理设备之间的数据传输。如读/写文件,网络通讯等。
    • 输入input:读取外部数据(磁盘、光盘等存储设备的数据)到程序(内存)中。

    • 输出output:将程序(内存)数据输出到磁盘、光盘等存储设备中。

2.2 流的分类

java.io包下提供了各种“流”类和接口,用以获取不同种类的数据,并通过标准的方法输入或输出数据。

  • 按数据的流向不同分为:输入流输出流

    • 输入流 :把数据从其他设备上读取到内存中的流。

      • 以InputStream、Reader结尾

    • 输出流 :把数据从内存 中写出到其他设备上的流。

      • 以OutputStream、Writer结尾

  • 按操作数据单位的不同分为:字节流(8bit)字符流(16bit)

    • 字节流 :以字节为单位,读写数据的流。

      • 以InputStream、OutputStream结尾

    • 字符流 :以字符为单位,读写数据的流。

      • 以Reader、Writer结尾

  • 根据IO流的角色不同分为:节点流处理流

    • 节点流:直接从数据源或目的地读写数据

    • 处理流:不直接连接到数据源或目的地,而是“连接”在已存在的流(节点流或处理流)之上,通过对数据的处理为程序提供更为强大的读写功能。

小结:图解

2.3 流的API

  • Java的IO流共涉及40多个类,实际上非常规则,都是从如下4个抽象基类派生的。

(抽象基类)输入流输出流
字节流InputStreamOutputStream
字符流ReaderWriter
  • 由这四个类派生出来的子类名称都是以其父类名作为子类名后缀。

常用的节点流:  

  • 文件流: FileInputStream、FileOutputStrean、FileReader、FileWriter

  • 字节/字符数组流: ByteArrayInputStream、ByteArrayOutputStream、CharArrayReader、CharArrayWriter

    • 对数组进行处理的节点流(对应的不再是文件,而是内存中的一个数组)。

常用处理流:

  • 缓冲流:BufferedInputStream、BufferedOutputStream、BufferedReader、BufferedWriter

    • 作用:增加缓冲功能,避免频繁读写硬盘,进而提升读写效率。

  • 转换流:InputStreamReader、OutputStreamReader

    • 作用:实现字节流和字符流之间的转换。

  • 对象流:ObjectInputStream、ObjectOutputStream

    • 作用:提供直接读写Java对象功能

3. 节点流之一:FileReader\FileWriter

3.1 Reader与Writer

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

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

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

3.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()方法,释放系统资源,否则会造成内存泄漏。

3.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()方法,释放系统资源,否则会造成内存泄漏。

3.2 FileReader 与 FileWriter

3.2.1 FileReader

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

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

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

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

/**
     * 需求:读取hello.txt中的内容,显示在控制台上。
     *
     * 异常使用throws的方式处理不太合适
     */
    @Test
    public void test() throws IOException {
        //1、创建File类的对象,对应着hello.txt文件
        File file = new File("hello2.txt");

        //2、创建输入型的字符流,用于读取数据
        FileReader fr = new FileReader(file);


        //3、读取数据,并显示在控制台上
        int data = fr.read();
        while (data!=-1){
            System.out.println((char)data);
            data = fr.read();
        }

        //4、流资源的关闭操作(必须要关闭,否则会内存泄露)
        fr.close();
    }

对以上案例进行优化,使用try-catch-finally处理异常,避免内存泄漏

/**
     * 需求:读取hello.txt中的内容,显示在控制台上。
     *
     * 使用try-catch-finally的方式处理异常,确保流一定可以关闭,避免内存泄露
     */
    @Test
    public void test2()  {
        FileReader fr = null;
        try {
            //1、创建File类的对象,对应着hello.txt文件
            File file = new File("hello2.txt");

            //2、创建输入型的字符流,用于读取数据
            fr = new FileReader(file);


            //3、读取数据,并显示在控制台上
            int data;
            while ((data = fr.read()) != -1){
                System.out.println((char)data);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //4、流资源的关闭操作(必须要关闭,否则会内存泄露)
            try {
                fr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

继续对以上代码进行优化,每次读取多个字符放到字符数组,减少与磁盘的交互,提升效率

/**
     * 需求:读取hello.txt中的内容,显示在控制台上。
     *
     * 对 test2()进行优化,每次读取多个字符放到字符数组中,减少了与磁盘交互的次数,提升效率。
     */
    @Test
    public void test3()  {
        FileReader fr = null;
        try {
            //1、创建File类的对象,对应着hello.txt文件
            File file = new File("hello2.txt");

            //2、创建输入型的字符流,用于读取数据
            fr = new FileReader(file);


            //3、读取数据,并显示在控制台上
           char[] cbuffer = new char[5];
            int len;
            while ((len = fr.read(cbuffer))!=-1){
                //遍历数组
                for (int i=0;i<len;i++){
                    System.out.println(cbuffer[i]);
                }
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //4、流资源的关闭操作(必须要关闭,否则会内存泄露)
            try {
                fr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

不同实现方式的类比:

3.2.2 FileWriter

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

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

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

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

/**
     *
     * 需求:将内存中的数据写出到指定的文件中
     */
    @Test
    public void test4() {
        FileWriter fw = null;
        try {
            //1、创建File类的对象,指明要写出这个文件的名称
            File file = new File("info.txt");
            //2、创建输出流
            fw = new FileWriter(file);  // 覆盖文件的构造器,如要追加,需要使用new FileWriter(file,true)这个构造器

            //3、写出的具体过程
            // 输出的方法:write(String str) / write(char[] cdata)
            fw.write("I love U!\n");
            fw.write("you love him\n");
            fw.write("太惨了。。。。。");
            fw.write("太惨了。。。。。");
            fw.write("太惨了。。。。。");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //4、关闭资源
            try {
                fw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

运行结果:

3.2.3 小结

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

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

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

4. 节点流之二:FileInputStream\FileOutputStream

如果我们读取或写出的数据是非文本文件,则Reader、Writer就无能为力了,必须使用字节流

4.1 InputStream和OutputStream

4.1.1 字节输入流:InputStream

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

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

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

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

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

说明:close()方法,当完成流的操作时,必须调用此方法,释放系统资源。

4.1.2 字节输出流:OutputStream

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

  • public void write(int b) :将指定的字节输出流。虽然参数为int类型四个字节,但是只会保留一个字节的信息写出。

  • public void write(byte[] b):将 b.length字节从指定的字节数组写入此输出流。

  • public void write(byte[] b, int off, int len) :从指定的字节数组写入 len字节,从偏移量 off开始输出到此输出流。

  • public void flush() :刷新此输出流并强制任何缓冲的输出字节被写出。

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

说明:close()方法,当完成流的操作时,必须调用此方法,释放系统资源。

4.2 FileInputStream 与 FileOutputStream

4.2.1 FileInputStream

java.io.FileInputStream类是文件输入流,从文件中读取字节。

  • FileInputStream(File file): 通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件系统中的 File对象 file命名。

  • FileInputStream(String name): 通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件系统中的路径名 name命名。

4.2.2 FileOutputStream

java.io.FileOutputStream类是文件输出流,用于将数据写出到文件。

  • public FileOutputStream(File file):创建文件输出流,写出由指定的 File对象表示的文件。

  • public FileOutputStream(String name): 创建文件输出流,指定的名称为写出文件。

  • public FileOutputStream(File file, boolean append): 创建文件输出流,指明是否在现有文件末尾追加内容。

示例:

import org.junit.Test;

import java.io.*;

/**
 * ClassName:IntelliJ IDEA
 * Description:
 *
 * @Author zyjstart
 * @Create:2024/10/10 17:11
 */
public class FileStreamTest {

    /**
     * 需求:复制一份qilongzhu.jpg文件,命名为qilongzhu_copy.jpg
     */
    @Test
    public void test1() {
        FileInputStream fis = null;
        FileOutputStream fos = null;

        try {
            //1、创建相关的File类的对象
            File srcFile = new File("qilongzhu.jpg");
            File destFile = new File("qilongzhu_copy.jpg");

            //2、创建相关的字节流
            fis = new FileInputStream(srcFile);
            fos = new FileOutputStream(destFile);

            //3、数据的读写操作
            byte[] buffer = new byte[1024]; //1kb
            int len;    //记录每次读入到buffer中的字节数
            while ((len = fis.read(buffer)) != -1){
                fos.write(buffer,0,len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //4、关闭资源
            try {
                if (fis != null)
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (fos != null)
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }
}

这样,我们就复制了一张图片到当前目录。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值