IO流:字节流、字符流、缓冲流、转换流、序列化流、打印流、小结

IO概述

学习IO流的目的:

实现数据的持久化。

什么是IO:

  1. Input:输入
  2. Output:输出
  • 输入输出称为IO操作

IO流的作用:

  • 输入:将文件中的数据读取到内存中。
  • 输出:将内存中的数据保存到文件中。

IO流分类:

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

  • 字节输入流:InputStream 所有字节输入流的父类 。
  • 字节输出流:OutputStream 所有字节输出流的父类。

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

  • 字符输入流:Reader 所有字符输入流的父类。
  • 字符输出流:Writer 所有字符输出流的父类。

IO流关闭资源的原则:

先开后关,后开先关。

如何判断流是字节流还是字符流:

如果是以Stream结尾的流,就是字节流,否则都是字符流。

字节流和字符流的区别:

  • 字节流:可以操作任意类型的文件 。
  • 字符流:只能用来操作文本文件。

字节流和字符流的选择:

  • 如果明确清楚要操作的文件类型是文本文件,则强烈推荐使用字符流 。
  • 如果不清楚要操作的文件类型是什么类型,则只能选择字节流。

IO流的使用步骤:

  1. 创建流关联目标文件。
  2. 调用流的write或read方法读写数据。
  3. 调用流的close方法关闭流释放资源。

数据的本质:

  1. 计算机只识别0和1。
  2. 所有的数据(文本文件,视频,图片,音频)在内存中存储都是0和1组成。
  3. 所有数据在传输过程中都是以0和1进行传输(二进制)。
  4. 数据的本质:二进制。
  • 编码:将字符转换为对应的二进制数据的过程。
  • 解码:将二进制数据转换为对应的字符的过程。

字节流

字节输出流(OutputStream)

OutputStream类概述:

  1. Output:输出。
  2. Stream: 字节流。
  3. 是一个字节输出流,以字节为单位输出数据到文件中。
  4. 是一个抽象类,不能直接创建该类的对象,只能创建子类对象。
  5. 是所有字节输出流的父类。

OutputStream类常用子类:

  1. FileOutStream
  2. BufferedOutputStream
  3. ObjectOutputStream
  4. PrintStream

OutputStream类常用方法:

void close()

  • 关闭流释放资源 。

void write(byte[] b)

  • 输出一个字节数组。

void write(byte[] b, int off, int len)

  • 输出一个字节数组的一部分内容。
  • off:数组的起始索引。
  • len:要输出的字节个数。

void write(int b)

  • 输出一个字节。如果数字超过一个字节的范围,比如两个字节。则忽略前面的字节,只取最后那个字节所对应的ASII码。

FileOutputStream类

FileOutputStream类常用构造方法:

FileOutputStream(String name)

  • 根据文件路径字符串创建字节输出流对象。
  • 如果目标文件不存在,则会创建该文件。

FileOutputStream(File file)

  • 根据文件对象创建字节输出流对象。
  • 如果目标文件不存在,则会创建该文件。
  • 关联的目标文件必须是普通文件,不能是文件夹,否则直接抛出异常。

​​​​​​​追加输出和换行输出数据:

FileOutputStream(File file, boolean append)

FileOutputStream(String name, boolean append)

  • 根据文件对象或文件路径字符串创建字节输出流对象。
  • append:true 表示追加输出数据,不清空当前文件的内容。
  • append:false 表示不追加输出数据,清空当前文件的内容。
  • 如果目标文件不存在,则会先创建该文件。
  • 根据文件对象创建对象时,关联的目标文件必须是普通文件,不能是文件夹,否则直接抛出异常。

字节输出流的使用步骤:

  1. 创建字节输出流对象并关联目标文件。
  2. 调用字节输出流对象的write方法输出数据。
  3. 调用字节输出流对象的close方法关闭流释放资源

换行符:

  1. \r  作用:回车
  2. \n   作用:换行,光标移到下一行的行首。
  3. \r\n   作用:换行,光标移到下一行的行首。 (强烈推荐使用
  • ​​​​​​​当下面没有内容的时候,回车跟换行的作用是一样的,但是当下面有内容时,作用就不一样。
  • window自带的记事本不能识别  \r  和  \n  。只能识别  \r\n  ,为了适配任何系统,所以推荐使用  \r\n 。 

追加和换行写出数据 示例代码:

public class FileOutputStreamDemo03 {
    public static void main(String[] args)throws Exception{
        // 创建字节输出流对象并关联目标文件
        FileOutputStream fos = new FileOutputStream("b.txt",true);
        // 将字符串输出到流关联目标文件中
        fos.write("abcde\r\nabcde".getBytes());
        // 关闭流释放资源
        fos.close();
    }
}

字节输入流(InputStream)

InputStream类概述:

  1. Input:输入。
  2. Stream:字节流。
  3. 是一个字节输入流,以字节为单位读取数据。
  4. 是一个抽象类,也不能创建给类对象,只能创建子类对象。
  5. 是所有字节输入流的父类。

InputStream类常用子类:

  1. FileInputStream
  2. BufferedInputStream
  3. ObjectInputStream

InputStream类常用方法:

void close()

  • 关闭流释放资源.

int read()

  • 读取一个字节,返回读取到的字节数.
  • 如果读取到文件末尾,则返回值为‐1.

​​​​​​​int read(byte[] b)

  • 读取一个字节数组,将读取到内容存储到指定的字节数组中。
  • 返回实际读取到的字节个数.
  • 如果读取到文件末尾,则返回值为‐1。

​​​​​​​int read(byte[] b, int off, int len)

  • 读取一个字节数组,将读取到内容存储到指定的字节数组中。
  • off:字节数组的起始索引。
  • len:存储字节的个数。

FileInputStream类

FileInputStream类常用构造方法:

FileInputStream(String name)

FileInputStream(File file)

  • 根据文件路径字符串或文件对象创建字节输入流对象。
  • 如果目标文件不存在,则直接抛出异常。
  • 关联的目标文件必须是普通文件,不能是文件夹,否则直接抛出异常。

如何把输入字符数组的字符转成字符串输出​​​​​​​:

String (byte[] b )

String(byte[] b , int off , int length)

  • 用这两个String的构造方法,可以把输入字符数组的字符转成字符串。

字符流

了解:

  • 字符流仅能文本文件进行操作 。
  • GBK编码表中,一个中文字符占3个字节 。
  • UTF-8编码表中,一个中文字符占2个字节​​​​​​​。

字符输入流(Reader)

Reader类概述:

  1. 是字符输入流,也是一个抽象类,不能创建对象,只能使用子类。
  2. 以字符为单位读取数据。
  3. 是所有字符输入流的父类。

Reader类常用子类:

  1. FileReader
  2. BufferedReader
  3. InputStreamReader

Reader类常用方法:

void close

  • 关闭流释放资源。

​​​​​​​int read()

  • 读取一个字符,返回实际读取的字符数。
  • 读取到文件末尾返回‐1。

​​​​​​​int read(char[] cbuf)

  • 读取一个字符数组,将读取到的字符存储到字符数组中。
  • 返回实际读取到的字符个数。
  • 读取到文件末尾返回‐1。

​​​​​​​int read(char[] cbuf, int off, int len)

  • 读取一个字符数组,将读取到内容存储到指定的字符数组中。
  • off:字符数组的起始索引。
  • len:存储字符的个数。

FileReader类

FileReader类常用构造方法:

FileReader(String name)

FileReader(File file)

  • 根据文件路径字符串或文件对象创建字符输入流对象。

字符输入流使用步骤:

  1. 创建字符输入流关联目标文件。
  2. 调用read方法:读取字符,字符数组。
  3. 调用close方法关闭流释放资源。

字符输出流(Writer)

Writer类概述:

  1. 是字符输出流,也是一个抽象类,不能创建对象,只能使用子类。
  2. 以字符为单位输出数据。
  3. 是所有字符输出流的父类。

Writer类常用子类:

  1. FileWriter
  2. BufferedWriter
  3. OutputStreamWriter
  4. PrintWriter

Writer类常用方法:

void close()

  • 关闭流,释放资源。

​​​​​​​void write(char[] cbuf)

  • 输出字符数组。

void write(char[] cbuf, int off, int len)​​​​​​​

  • 输出字符数组的一部分。

​​​​​​​void write(int c)

  • 输出一个字符。

​​​​​​​字节流没有,字符流独有的方法:

void write(String str)

  • 输出字符串。

​​​​​​​void write(String str, int off, int len)

  • 输出字符串的一部分。

FileWriter类

FileWriter类常用构造方法:

FileWriter(String name)

FileWriter(File file)

  • 默认是不追加,会清空文件内容。

​​​​​​​FileWriter(String name,boolean append)

FileWriter(File file,boolean append)

  • 根据文件路径字符串和文件对象创建字符输出流对象。
  • append:true 追加
  •                 false:不追加

缓冲流

缓冲流概述:

缓冲流又称为高效流。

  • 缓冲流的使用方式和非缓冲流使用方式是一样的,区别在构造方法不一样而已。

缓冲流的分类:

  • ​​​​​​​字节缓冲输出流:BufferedOutputStream
  • 字节缓冲输入流:BufferedInputStream
  • 字符缓冲输出流:BufferedWriter
  • 字符缓冲输入流:BufferedReader

缓冲流的原理:

  • 利用缓冲区数组临时存储多个数据,等缓冲区数组满了或调用了close方法时,一次调用或减少底层资源的调用次数从而提高读写速度。

图解:

IO流:字节流、字符流、缓冲流、转换流、序列化流、打印流、小结_第1张图片

字节缓冲流

字节输出缓冲流

BufferedOutputStream类概述:

  • 继承OutputStream,是字节缓冲输出流,可以往任意类型的文件输出数据。

BufferedOutputStream类构造方法:

BufferedOutputStream(OutputStream out)

  • 根据字节输出流创建字节缓冲输出流对象。
  • 传递谁就提高谁的效率。
  • 注意:缓冲输出流的构造方法没有追不追加一说,如果要想可以追加输出,则传递的参数FileOutputStream可以追加。
  • 缓冲区数组默认size:8192

BufferedOutputStream类使用注意事项:

  • 调用缓冲流的write方法输出数据不是直接输出到目标文件中,而是先输出到缓冲区数组中,等缓冲区数组满了或调用了flush或close方法才会将缓冲区数组的数据通过FileOutputStream输出到目标文件中。

void flush()

  • 刷新缓冲区。

close和flush方法的区别:(面试题

  • flush刷新缓冲区,flush方法调用之后流还可以继续使用。
  • close关闭流释放资源,close方法调用之后流就不能继续使用了,close会调用flush方法先刷新缓冲区,然后再关闭流释放资源。

字节输入缓冲流

BufferedInputStream类概述:

继承InputStream,字节缓冲输入流,可以读取任意类型文件的数据。

BufferedInputStream类构造方法:

BufferedInputStream(InputStream in)

  • 根据字节输入流创建字节缓冲输入流对象。
  • 传递谁就提高谁的效率。

BufferedInputStream类使用注意事项:

  • 利用字节缓冲输入流读取数据时不是直接从目标文件中读取,而是从缓冲区数组中读取,如果缓冲区数组中没有数据可读了,则会利用FileInputStream流从目标文件中读取数据到 缓冲区数组中,一次从目标文件中读取8192字节到数组中。

字符缓冲流

字符缓冲输出流

BufferedWriter类概述:

  • 继承Writer,是字符缓冲输出流,只能往文本文件中输出数据。

BufferedWriter类构造方法:

BufferedWriter(Writer writer)

  • 根据字符输入流创建字符缓冲输入流对象。
  • 传递谁就提高谁的效率。

BufferedWriter类特有方法:

void newLine()

  • 输出一个换行符。

字符缓冲输入流

BufferedReader类概述:

  • 继承Reader,字符缓冲输入流,只能读取文本文件的内容。

BufferedReader类构造方法:

BufferedReader(Reader r)

  • 根据字符输出流创建字符缓冲输出流对象。
  • 传递谁就提高谁的效率。

BufferedReader类特有方法:

String readLine()

  • 读取一行数据,读取到文件末尾返回null

转换流

码表的概述:

  1. 码表其实就是一个字符和其对应的二进制相互映射的一张表。
  2. 这张表中规定了字符和二进制的映射关系。
  3. 不同的码表所容纳的字符映射也是不同的。
  • GBK编码表中,一个中文字符占3个字节 。
  • UTF-8编码表中,一个中文字符占2个字节​​​​​​​。

乱码的原因:

因为文本在存储时使用的码表和读取时使用的码表不一致造成的。 

转换流概述:

本质就是字符流。

转换流存在的意义:

可以指定码表来读写数据。

转换流的分类:

  1. 字符转换输入流:  InputStreamReader
  2. 字符转换输出流:  OutputStreamWriter

InputStreamReader类

InputStreamReader类概述:

  1. 继承Reader,字符转换输入流,只能读取文本文件的内容。
  2. 字节流通向字符流的桥梁(字节转字符)。

InputStreamReader类构造方法:

InputStreamReader(InputStream in)

  • 根据字节输入流创建字符转换输入流,默认的编码表:utf8。

​​​​​​​InputStreamReader(InputStream in, String charsetName)

  • 根据字节输入流创建字符转换输入流。
  • charsetName:用来指定编码的名称,常用的编码表名:gbk和utf8。

字符转换输入流的转换流程:

  1. 先由字节输入流从目标文件中读取数据,读出来的是一堆二进制数据。
  2. 然后将读取到的二进制数据交个字符转换流,由字符转换流查询指定的码表将二进制数据转换为对应的字符。

OutputStreamWriter类

OutputStreamWriter类概述:

  1. 继承Writer, 字符转换输出流,只能往文本文件中输出数据。
  2. 是字符流通向字节流的桥梁(字符转换字节)。

OutputStreamWriter类构造方法:

OutputStreamWriter(OutputStream out) 默认的编码表:utf8

OutputStreamWriter(OutputStream out,String charsetName)

  • 根据字节输出流创建字符转换输出流对象。
  • charsetName:用来指定编码的名称,常用的编码表名:gbk和utf8。

字符转换输出流的转换流程:

  1. 先由字符转换输出流查询指定的码表将字符转换为二进制数据。
  2. 然后将二进制数据交给字节输出流输出到目标文件中。

序列化流

序列化流的作用​​​​​​​:

  1. 可以直接将对象保存到文件中。
  2. 可以直接从文件中读取对象。

序列化流的分类:

  • ObjectOutputStream:对象输出流
  • ObjectInputStream:对象输入流

对象的序列化:

  1. 将对象以流的形式保存到文件中的过程则称为对象的序列化。
  2. 实现对象序列化操作需要使用对象输出流:ObjectOutputStream。

对象的反序列化:

  1. 将文件中的对象以流的形式读取出来的过程则称为对象的反序列化。
  2. 实现对象的反序列化操作需要使用对象输入流:ObjectInputStream。

对象序列化注意事项:

  • 对象序列化操作只会保存对象相关的数据,属于类的数据不会被保存,因为static修饰的成员变量是属于类的 所以在保存对象时静态成员变量的值不会被保存。

ObjectOutputStream类

ObjectOutputStream类构造方法:

ObjectOutputStream(OutputStream out)

  • 根据字节输出流创建对象输出流对象。

ObjectOutputStream类成员方法:

void writeObject(Object obj)

  • 保存对象到流关联的文件中。

若类要想被序列化,则必须实现Serializable接口

Serializable接口概述:

  1. 是一个标志性接口,只要实现了该接口就具备序列化能力。
  2. 只有实现了该接口的类的对象,才可以通过对象输出流保存到文件中。

若类不实现该接口,用对象输出流保存在文件文件中,则会报错:

java.io.NotSerializableException:  对象不支持序列话操作。

若希望类的某项数据不被保存,有两种方法:

  1. 用static修饰变量。
  2. 用transient修饰变量。

transient关键字作用:

  • 用来修饰成员变量的,能够保证该成员变量的值不被序列化到文件中。

transient关键字的格式:

修饰符 transient 数据类型 成员变量名;

 ObjectInputStream类

ObjectInputStream类构造方法:

ObjectInputStream(InputStream in)

  • 根据字节输入流创建对象输入流。

ObjectInputStream类成员方法:

Object readObject();

  • 从流关联的目标文件中读取对象。

示例代码:

public class ObjectInputStreamDemo01 {
    public static void main(String[] args)throws Exception{
        // 创建对象输入流对象
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("stu.txt"));
        // 读取对象数据
        Student stu = (Student)ois.readObject(); // new Student() Student.class
        System.out.println(stu);
        // 关闭流
        ois.close();
    }
}

如果实现Serializable接口的类被序列化保存到文件中,如果对类进行修改,再对类反序列化,则会报错。

  • java.io.InvalidClassException  : 序列化冲突。
  • 一旦类实现了Serializable接口,每当类重新编译系统都会为类随机生成一个序列号。
  • 序列号是一个长整型的数据。

序列号冲突解决方案:

自定义序列号,格式如下:

  • private static final long serialVersionUID = 132456789765L;

若想存储多个对象,则可以把多个对象弄到ArrayList里,再序列化ArrayList对象。

示例代码:

import java.io.*;
import java.util.ArrayList;
import java.util.Collections;

public class Demo1 {
    public static void main(String[] args) throws Exception {
        Student s1 = new Student("aa",15);
        Student s2 = new Student("bb",16);
        Student s3 = new Student("cc",19);
        ArrayList list = new ArrayList<>();
        Collections.addAll(list,s1,s2,s3);
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("stu.txt")));
        oos.writeObject(list);
        oos.close();

    }
}

import java.io.File;
import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.util.ArrayList;

public class Demo2 {
    public static void main(String[] args) throws Exception{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("stu.txt")));
        ArrayList list = (ArrayList)ois.readObject();
        for (Student student : list) {
            System.out.println(student);
        }

    }
}

打印流

打印流存在的意义:

为了方便原样输出各种数据类型的值。

打印流的特点:

  1. 只有输出流,没有输入流。
  2. 能够原样输出各种数据类型的值。

打印流的分类:

  • 字节打印流:PrintStream 可以往任意类型的文件打印数据。
  • 字符打印流:PrintWriter 只能往文本文件中打印数据。

打印流常用方法:

print(数据类型 变量名)

  • 将数据输出到目标文件中,不换行。

​​​​​​​println(数据类 变量名)

  • 将数据输出到目标文件中,自动换行。

PrintWriter类

构造方法:

public PrintWriter(String fileName)

  • 使用指定的文件名创建一个新的打印流。

PrintStream类

构造方法:

public PrintStream

  • 使用指定的文件名创建一个新的打印流。
  • System.out 就是 PrintStream 类型的,只不过它的流向是系统规定的,打印在控制台上。
  • 我们可以用System.setOut(PrintStream p)改变sout的流向。

示例代码:

public static void test() throws IOException {
        // 调用系统的打印流,控制台直接输出97
        System.out.println(97);
        PrintStream consolePs = System.out;
        // 创建打印流,指定文件的名称
        PrintStream ps = new PrintStream("ps.txt");
        // 设置系统的打印流流向,输出到ps.txt
        System.setOut(ps);
        // 调用系统的打印流,ps.txt中输出97
        System.out.println(97);
        // 设置系统的打印流流向
        System.setOut(consolePs);
        System.out.println(98);
}

​​​​​​​IO流小结

字节流输入流:InputStream 所有字节输入流的父类:

  • FileInputStream:字节非缓冲输入流,效率低,不推荐直接使用 。
  • BufferedInputStream:字节缓冲输入流,效率高,推荐使用 。
  • ObjectInputStream:对象输入流,当需要从文件中读取自定义对象时使用。

字节输出流:OutputStream 所有字节输出流的父类:

  • FileOutputStream:字节非缓冲输出流 效率低,不推荐直接使用 。
  • BufferedOutputStream:字节缓冲输出流,效率高,推荐使用 。
  • ObjectOutputStream:对象输出流,当需要保存自定义对象到文件中时使用 。
  • PrintStream:字节打印流,当希望原样输出各种数据类型的值时使用 。

字符流输入流:Reader 所有字符输入流的父类:

  • FileReader:字符非缓冲输入流,效率低,不推荐直接使用 。
  • BufferedReader:字符缓冲输入流,效率高,推荐使用 。
  • InputStreamReader:字符转换输入流,当需要修改默认码表去读数据时使用,否则不推荐使用。

字符输出流:Writer 所有字符输出流的父类:

  • ​​​​​​​FileWriter:字符非缓冲输出流 ,效率低,不推荐直接使用。
  • BufferedWriter:字符缓冲输出流,效率高,推荐使用 。
  • OutputStreamWriter:字符转换输出流,当需要修改码表去输出数据时使用 。
  • PrintWriter:字符打印流,当希望原样输出各种数据类型的值时使用。​​​​​​​

 

你可能感兴趣的:(知识点的整理)