带你轻松理清Java IO体系⏳

844 阅读19分钟

IO流

🚦JavaIO流,是一种计算机用语。主要是用于处理数据的传输流。IO流有四大抽象类,分别是Reader、Writer、InputStream、OutputStream,接下来将根据这四大抽象类来展开介绍。

IO流的分类

  • 按流的流向分,可以分为输入流InputStream输出流OutputStream
  • 按处理数据单位,可以划分为字节流(InputStream、OutputStream)字符流(Reader、Writer)
  • 按流的角色划分为节点流(直接与数据源相连接进行读写,不方便)和处理流(在节点流的基础上,再套接上一层,成为处理流,效率高,如BufferedInputStrean)。

🚩🚩注意:输入流只能读数据,而输出流只能写数据,所以我们需要根据待传输数据的不同特性而使用不同的流。

按操作方式划分

  • 节点流:FileInputStream、FileReader
  • 处理流:BufferedWriter、BufferedInputStreamimage.png

🚩🚩注意:这里的读取、写出是从内存的角度出发的,如字符读取是指硬盘文件中的数据以字符的方式读取到内存中,写出是指把内存中的数据写出到硬盘的文件中。

按操作对象划分

  1. 文件操作:FileInputStream、FileOutputStream、FileReader、FileWriter

  2. 管道操作:PipedInputStream

  3. 数组操作:

    • 字符数组:CharArrayReader、CharArrayWriter

    • 字节数组:ByteArrayInputStream、ByteArrayOutputStream

  4. 缓冲操作:BufferedWriter、BufferedInputStream

  5. 基本数据类型操作:DataOutputStream、DataInputStream

  6. 对象序列化操作:ObjectOutputStream、ObjectInputStream

  7. 转化操作:InputStreamReader、OutputStreamWriter

  8. 打印控制:PrintStream、PrintWriter

image.png

字节输入流InputStream

InputStream是所有表示字节输入流的类的父类,InputStream是一个抽象类,抽象类无法直接创建对象,所以我们需要使用其子类,InputStream常见的子类有FileInputStream文件字节输入流表示从本地文件中读取数据、ByteArrayInputStream字节数组输入流表示从字节数组中读取数据、StringBufferInputStream字符串缓冲输入流表示从字符串缓冲中读取数据。

InputStream中定义的一些子类共性的成员方法

  • public abstract int read() 从输入流中读取一个数据,返回的是数据的ASCII值

  • public int read(byte[] b) 从输入流中读取一定数量的字节,默认从第0个位置读取b.length长度的数据,参数byte[]数组表示起缓冲作用,存储每次读取的多个字节。

  • int read(byte b[], int off, int len)从第 off 位置读取 len 长度字节的数据放到byte数组中

  • int available() 返回可读的字节数量

  • long skip(long n) 跳过指定个数的字节不读取

  • public void close() 关闭此输入流并释放与该流关联的所有系统资源

FileInputStream文件字节输入流

文件字节输入流是直接继承InputStream的,java.io.FileInputStream extends InputStream,FileInputStream表示从本地文件中读取数据到内存中。

FileInputStream的常用构造方法

  • public FileInputStream(String name),通过打开与实际文件的连接创建一个FileInputStream,参数name表示所要读取的本地文件的全路径名称。
public FileInputStream(String name) throws FileNotFoundException {
    this(name != null ? new File(name) : null);
}
  • public FileInputStream(File file) 通过打开与实际文件的连接创建一个FileInputStream,参数file表示所要读取的文件的File对象
public FileInputStream(File file) throws FileNotFoundException {
    String name = (file != null ? file.getPath() : null);
    SecurityManager security = System.getSecurityManager();
    if (security != null) {
        security.checkRead(name);
    }
    if (name == null) {
        throw new NullPointerException();
    }
    if (file.isInvalid()) {
        throw new FileNotFoundException("Invalid file path");
    }
    fd = new FileDescriptor();
    fd.attach(this);
    path = name;
    open(name);
    FileCleanable.register(fd);       // open set the fd, register the cleanup
}

FileInputStream的使用

//1、创建一个FileInputStream对象,构造方法中传递写入数据的目的地
FileInputStream fis = new  FileInputStream("C:\\Java\\test.txt");

//或通过File文件对象来创建FileInputStream
File file = new File(C:\\Java\\test.txt");
FileInputStream fis2 = new FileInputStream(file);


//2.1调用FileInputStream对象中的方法read,从该输入流中读取一个字节的数据
int s = fis.read();
System.out.println((char)s);

//2.2或循环读取整个文件数据
int data=0;
//返回数据的下一个字节,如果到达文件末尾则返回-1
while((data=fis.read())!=-1){
    System.out.println((char)data);
}

//2.3或从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中
byte[] b = new byte[6];
//存储到数组b中
fis.read(b);
//将字节数组转换成字符串输出
String s1 = new String(b);
System.out.println(s1);

//3.关闭流
fis.close();

ByteArrayInputStream字节数组输入流

ByteArrayInputStream字节数组输入流是指从指定的字节数组中读取数据到内存中

ByteArrayInputStream的构造方法

  • public ByteArrayInputStream(byte buf[]) 传入一个指定的缓冲区容量
public ByteArrayInputStream(byte buf[]) {
    this.buf = buf;
    this.pos = 0;
    this.count = buf.length;
}
  • public ByteArrayInputStream(byte buf[], int offset, int length)
/**
* @param   buf      缓冲区容量
* @param   offset   从字节数组要读的第一个字节的索引下标
* @param   length   从字节数组中读取的最大字节数
*/
public ByteArrayInputStream(byte buf[], int offset, int length) {
    this.buf = buf;
    this.pos = offset;
    this.count = Math.min(offset + length, buf.length);
    this.mark = offset;
}

ByteArrayInputStream的使用

public static void main(String[] args) {
    byte[] bytes = {97,98,99,100};
    //从字节数组的索引下标为1的位置开始读取2个元素
    ByteArrayInputStream bais = new ByteArrayInputStream(bytes,1,2);
    int data;
    while((data =bais.read())!=-1){
        System.out.print(data);
    }
    输出:9899
}

字节输出流OutputStream

OutputStream是所有表示字节输出流的类的父类,OutputStream是一个抽象类,抽象类无法直接创建对象,所以我们需要使用其子类,OutputStream常见的子类有FileOutputStream文件字节输入流表示往本地文件中写入数据、ByteArrayOutputStream字节数组输入流表示将内存中的数据写到指定的字节数组中。

OutputStream中定义的一些子类共性的成员方法

  • void close() 关闭此输出流并释放与此流有关的所有系统资源

  • void flush() 刷新此输出流,将缓冲区中的数据写出

  • abstract void write(int b) 将指定的字节写入此输出流

  • void write(byte[] b) 将 b.length 个字节从指定的 byte 数组写出

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

FileOutPutStream文件字节输出流

文件字节输出流是直接继承OutputStream的,java.io.FileOutputStream extends OutputStream,FileOutputStream表示将内存中的数据写入到文件中。

FileOutputStream的常用构造方法

  • FileOutputStream(String name, boolean append) 根据存在的文件的全路径名称创建一个FileOutputStream流,append表示是否追加写
public FileOutputStream(String name, boolean append)
    throws FileNotFoundException
{
    this(name != null ? new File(name) : null, append);
}
  • FileOutputStream(String name)根据存在的文件的全路径名称创建一个FileOutputStream流,append默认为false,不追加写
public FileOutputStream(String name) throws FileNotFoundException {
    this(name != null ? new File(name) : null, false);
}
  • FileOutputStream(File file)根据指定的File对象创建FileOutputStream输出流,默认append为false,不追加写。
public FileOutputStream(File file) throws FileNotFoundException {
    this(file, false);
}
  • FileOutputStream(File file, boolean append)根据指定的File对象创建FileOutputStream输出流,append表示是否追加写
public FileOutputStream(File file, boolean append)
    throws FileNotFoundException
{
    String name = (file != null ? file.getPath() : null);
    SecurityManager security = System.getSecurityManager();
    if (security != null) {
        security.checkWrite(name);
    }
    if (name == null) {
        throw new NullPointerException();
    }
    if (file.isInvalid()) {
        throw new FileNotFoundException("Invalid file path");
    }
    this.fd = new FileDescriptor();
    fd.attach(this);
    this.path = name;

    open(name, append);
    FileCleanable.register(fd);   // open sets the fd, register the cleanup
}

FileOutputStream的使用

public static void main(String[] args) throws IOException {
    FileOutputStream fos = new FileOutputStream("C:\Study\aaa.tx",true);
    byte[] b ={99,98,97};
    //将字节数组b写入到输出流中
    fos.write(b);
    fos.close();
}

ByteArrayOutputStream字节数组输出流

ByteArrayOutputStream字节数组输出流表示将内存中的数据写到字节数组输出流中,字节数组输出流会将数据写入到定义的缓冲区中,默认缓冲区大小为32,会自动扩容,可以通过toByteArray()方法将此输出流的当前内容,作为字节数组输出。

ByteArrayOutputStream的构造方法

  • ByteArrayOutputStream(),创建一ByteArrayOutputStream流,使用默认的缓冲区容量32
public ByteArrayOutputStream() {
    this(32);
}
  • ByteArrayOutputStream(int size) 根据指定的size值创建一个指定缓冲区容量的ByteArrayOutputStream流。
public ByteArrayOutputStream(int size) {
    if (size < 0) {
        throw new IllegalArgumentException("Negative initial size: "
                                           + size);
    }
    buf = new byte[size];
}

ByteArrayOutputStream的使用

public static void main(String[] args) throws IOException {
    //创建一个文件输入流
    FileInputStream in = new FileInputStream(new File("C:\Study\aaa.txt"));
    //创建一个字节数组输出流
    ByteArrayOutputStream out = new ByteArrayOutputStream();

    int data = 0;
    //循环遍历文件输入流中的数据
    while((data = in.read()) != -1){
        //将数据写出到字节数组的缓冲区中
        out.write(data);
    }
    //获取内存缓冲区中的数据
    byte[] bytes = out.toByteArray();
    for (int i = 0; i < bytes.length; i++) {
        System.out.println((char)bytes[i]);
    }

    in.close();
    out.close();

}

字符读取Reader

Reader是用于读取字符的抽象类,其直接子类有FileReader文件字符输入流,把文件中的数据以字符的方式读取到内存中、BufferedReader缓冲字符输入流,实现从字符输入流读取数据,然后缓冲字符,以提供高效的数据读取、还有InputStreamReader也是Reader一个非常重要的子类,它可以实现字节流和字符流之间的转换

Reader中定义的一些子类共性的成员方法

  • int read(CharBuffer target) 读取字节到字符缓存中
  • int read() 读取单个字符
  • int read(char cbuf[]) 读取字符到指定的 char 数组中
  • int read(char cbuf[], int off, int len) 从 off 位置读取 len 长度的字符到 char 数组中
  • long skip(long n) 跳过指定长度的字符数量不读取

FileReader

FilReader是直接继承于InputStreamReader的,实现按字符读取流中数据。我们通过FileReader来调用read()等方法,其实都是直接使用他的父类InputStreamReader的。FilReader类中只有构造方法,没有成员方法和属性。

FileReader的构造方法

  • FileReader(String fileName) 根据本地文件的全路径名创建一个文件字符输入流
public FileReader(String fileName) throws FileNotFoundException {
    super(new FileInputStream(fileName));
}
  • FileReader(File file) 根据一个File对象创建一个文件字符输入流。
public FileReader(File file) throws FileNotFoundException {
    super(new FileInputStream(file));
}
  • FileReader(String fileName, Charset charset) 根据本地文件的全路径名创建一个文件字符输入流,并指定字符集
public FileReader(String fileName, Charset charset) throws IOException {
    super(new FileInputStream(fileName), charset);
}
  • FileReader(File file, Charset charset)根据一个File对象创建一个文件字符输入流,并指定字符集。
public FileReader(File file, Charset charset) throws IOException {
    super(new FileInputStream(file), charset);
}

FileReader的使用

public static void main(String[] args) throws IOException {
    FileReader fileReader = new FileReader(new File("C:\Study\aaa.txt"));
    int data;
    while ((data =fileReader.read()) != -1) {
        System.out.println(data);
    }
}

字符写出Writer

Writer是JavaIo中的写出字符流,Writer跟Reader同样都是一个抽象类,其主要的子类有FileWriter文件字符写出流、BufferedWriter缓存字符流、OutputStreamWriter实现字符流转换为字节

🚲Writer一些子类共性的方法

  • void write(int c) 写入一个字符
  • void write(char cbuf[]) 写入一个字符数组
  • void write(char cbuf[], int off, int len) 从字符数组的 off 位置写入 len 数量的字符
  • void write(String str) 写入一个字符串
  • void write(String str, int off, int len) 从字符串的 off 位置写入 len 数量的字符
  • Writer append(CharSequence csq)以追加的方式写入一个字符序列
  • public void flush() 强制刷新,将缓冲区中的数据写入

FileWriter

FileWriter是直接继承OutputStreamWriter的,其中只包含多个构造方法,没有属性和成员方法,都是调用父类OutputStreamWriter的方法。

🛹FileWriter的几个构造方法

  • FileWriter(String fileName) 根据存在的文件的全路径文件名称来创建一个文件字符写出流
public FileWriter(String fileName) throws IOException {
    super(new FileOutputStream(fileName));
}
  • FileWriter(String fileName, boolean append)以上一个构造方法相比多了一个append,表示是否追加写,默认为否。
public FileWriter(String fileName, boolean append) throws IOException {
    super(new FileOutputStream(fileName, append));
}
  • FileWriter(File file)根据一个文件对象File来创建一个FileWriter文件字符写出流。
public FileWriter(File file) throws IOException {
    super(new FileOutputStream(file));
}
  • FileWriter(File file, boolean append)
public FileWriter(File file, boolean append) throws IOException {
    super(new FileOutputStream(file, append));
}
  • FileWriter(String fileName, Charset charset) 根据指定的编码和文件名称创建一个文件字符写出流。
public FileWriter(String fileName, Charset charset) throws IOException {
    super(new FileOutputStream(fileName), charset);
}
如下使用方式:

FileWriter fileWriter = new FileWriter("C:\Study\aaa.txt", Charset.forName("UTF-8"));

  • FileWriter(String fileName, Charset charset, boolean append)
public FileWriter(String fileName, Charset charset, boolean append) throws IOException {
    super(new FileOutputStream(fileName, append), charset);
}

🛴FileWriter的使用

public static void main(String[] args) throws IOException {
    FileWriter fw = new FileWriter(new File("C:\Study\aaa.txt"));
    fw.write("FileWriter");
    fw.close();
}

转换流

InputStreamReader 实现将字节流转换为字符流。是字节流通向字符流的桥梁。如果不指定字符集编码,该解码过程将使用平台默认的字符编码UTF-8。OutputStreamWriter实现将字符流转换为字节流。是字符流通向字节流的桥梁。如果不指定字符集编码,该解码过程将使用平台默认的字符编码UTF-8。

InputStreamReader 

InputStreamReader类是从字节流到字符流的桥梁,它使用指定的字符编码读取字节并将它们解码为字符

🏍InputStreamReader的几个构造方法

  • InputStreamReader(InputStream in) 创建一个使用默认字符集的InputStreamReader流。
public InputStreamReader(InputStream in) {
    super(in);
    try {
        sd = StreamDecoder.forInputStreamReader(in, this, (String)null); // ## check lock object
    } catch (UnsupportedEncodingException e) {
        // The default encoding should always be available
        throw new Error(e);
    }
}
  • InputStreamReader(InputStream in, Charset cs) 创建一个使用给定字符集的InputStreamReader
public InputStreamReader(InputStream in, Charset cs) {
    super(in);
    if (cs == null)
        throw new NullPointerException("charset");
    sd = StreamDecoder.forInputStreamReader(in, this, cs);
}
  • InputStreamReader(InputStream in, String charsetName) 创建一个使用命名字符集的InputStreamReader
public InputStreamReader(InputStream in, String charsetName)
    throws UnsupportedEncodingException
{
    super(in);
    if (charsetName == null)
        throw new NullPointerException("charsetName");
    sd = StreamDecoder.forInputStreamReader(in, this, charsetName);
}

🛹常用API

  • String getEncoding() 返回此流使用的字符编码的名称
  • int read() 读取一个字符

🏍InputStreamReader的使用

public static void main(String[] args) throws IOException {
    //a:创建InputStreamWriter对象,构造方法中传递字节输入流InputStream和指定的编码
    FileInputStream fis = new FileInputStream("C:\Study\a.txt");
    InputStreamReader isw = new InputStreamReader(fis,"utf-8");

    //:使用InputStreamWriter对象中的方法read读文件
    int len=0;
    while((len=isw.read())!=-1){
        System.out.print((char)len);
    }
    //c:释放资源
    isw.close();
    fis.close();

}

OutputStreamWriter

🚲OutputStreamWriter的几个构造方法

  • OutputStreamWriter(OutputStream out) 创建一个使用默认字符编码的OutputStreamWriter流
public OutputStreamWriter(OutputStream out) {
    super(out);
    try {
        se = StreamEncoder.forOutputStreamWriter(out, this, (String)null);
    } catch (UnsupportedEncodingException e) {
        throw new Error(e);
    }
}
  • OutputStreamWriter(OutputStream out, Charset cs) 创建一个使用给定字符集的OutputStreamWriter流
public OutputStreamWriter(OutputStream out, Charset cs) {
    super(out);
    if (cs == null)
        throw new NullPointerException("charset");
    se = StreamEncoder.forOutputStreamWriter(out, this, cs);
}
  • OutputStreamWriter(OutputStream out, String charsetName) 创建一个使用命名字符集的OutputStreamWriter流
public OutputStreamWriter(OutputStream out, String charsetName)
    throws UnsupportedEncodingException
{
    super(out);
    if (charsetName == null)
        throw new NullPointerException("charsetName");
    se = StreamEncoder.forOutputStreamWriter(out, this, charsetName);
}

🛴常用API

  • void flush() 刷新流。
  • String getEncoding() 返回此流使用的字符编码的名称。
  • void write(char[] cbuf, int off, int len) 写入字符数组的一部分。
  • void write(int c) 写一个字符
  • void write(String str, int off, int len) 写一个字符串的一部分

🛵OutputStreamWriter的使用

public static void main(String[] args) throws IOException{
    //a:创建OutputStreamWriter对象,构造方法中传递字节输出流OutputStream和指定的编码表
    FileOutputStream os = new FileOutputStream("C:\Study\a.txt",true);
    OutputStreamWriter osw = new OutputStreamWriter(os,"utf-8");

    //b:使用OutputStreamWriter对象中的方法write,把字符转换成字节存储到缓冲区中(编码)
    osw.write("不喝奶茶的Programmer");

    //c:使用OutputStreamWriter对象中的方法flush,把内存缓冲区中的字节刷新到文件中(使用字节流写字节的过程)
    osw.flush();

    //释放资源
    osw.close();

}

缓冲流

缓冲流也叫高效流,是对4种基本流的增强。

  • 字节缓冲流:BufferedOutputStream字节缓冲输出流,BufferedInputStream字节缓冲输入流.

  • 字符缓冲流:BufferedReader字符缓冲输出流,BufferedWriter字符缓冲输入流.

🚦缓冲流的基本原理:是在创建流对象时,会创建一个内置默认大小的缓冲区数组,通过缓冲区读写,减少系统IO次数,从而提高读写效率.

BufferedWriter

BufferWriter字符缓冲写出流是直接继承Writer的,实现将文本写入字符输出流,缓冲字符,以便有效地写入字符。

🏎BufferedWriterr的构造方法

  • BufferedWriter(Writer out) 根据字符写出流创建一个字符缓冲写出流,缓冲区默认大小是8192个字符
public BufferedWriter(Writer out) {
    this(out, defaultCharBufferSize);
}
  • BufferedWriter(Writer out, int sz) 根据字符写出流和指定的缓冲区大小创建一个字符缓冲写出流
public BufferedWriter(Writer out, int sz) {
    super(out);
    if (sz <= 0)
        throw new IllegalArgumentException("Buffer size <= 0");
    this.out = out;
    cb = new char[sz];
    nChars = sz;
    nextChar = 0;
}

🚡BufferedWriter的使用

public static void main(String[] args) throws IOException {

    BufferedWriter bw = new BufferedWriter(new FileWriter("C:\Users\23190\Desktop\Study\aaa.txt"));

    bw.write("BufferedWriter");

    bw.close();

}

BufferedReader

BufferedReader缓冲字符输入流是直接继承Reader抽象的,实现从字符输入流中读取文本并缓冲字符,以便有效地读取字符。

BufferedReader的构造方法

  • BufferedReader(Reader in)创建默认大小的输入缓冲区缓冲字符输入流
public BufferedReader(Reader in) {
    this(in, defaultCharBufferSize);
}
  • BufferedReader(Reader in, int sz) 创建一个使用指定大小为sz的输入缓冲区的缓冲字符输入流
public BufferedReader(Reader in, int sz) {
    super(in);
    if (sz <= 0)
        throw new IllegalArgumentException("Buffer size <= 0");
    this.in = in;
    cb = new char[sz];
    nextChar = nChars = 0;
}

BufferedReader的常用API

  • int read() 一次读取一行字符数据

  • int read(char[] cbuf, int off, int len) 将最多leng个字符读入数组中,返回实际读入的字符个数,当读取到文件末尾时,返回-1。

  • String readLine() 读一行文字并返回该行字符,若读到文件末尾,则返回null:即当遇到换行符('\ n'),回车符('\ r')时会终止读取表示该行文字读取完毕且返回该行文字(不包含换行符和回车符)

  • Stream<String> lines() 返回一个 Stream ,其元素是从这个 BufferedReader读取的行。

  • close()方法:关闭资源,释放链接。

BufferedReader的使用 🌵以下使用到Stream流,关于Stream流的相关知识,家可以看我的另一篇文章 ✈ JDK8新特性之Stream流

public static void main(String[] args) throws IOException {
    BufferedReader br = new BufferedReader(new FileReader("C:\Users\23190\Desktop\Study\aaa.txt"));

    //2.1第一种方式,将字符读取到字符数组中
    char[] cs = new char[1024];
    int count = 0;
    while ((count = br.read(cs)) != -1) {
        System.out.println(new String(cs, 0, count));
    }

    //2.2第二种方式,一行一行的读取
    String line = null;
    //注意这里while判断不再是-1了
    while ((line = br.readLine()) != null) {
        System.out.println(line);
    }
    
    //获取Stream流并对流中数据进行操作
    Stream<String> lines = br.lines();
    lines.filter((str)->{
        return str.equals("ab");
    }).forEach((str)->{
        System.out.println(str);
    });

    
    br.close();

}

BufferedInputStream 字节缓冲输入流

构造方法

  • BufferedInputStream(InputStream in) 根据InputStream输入流创建一个 BufferedInputStream。
  • BufferedInputStream(InputStream in, int size) 根据InputStream输入流和指定的缓冲区大小创建一个BufferedInputStream。

BufferedInputStream的使用

//a:创建FileInputStream对象,构造方法中绑定要读取的数据源
FileInputStream fis = new FileInputStream("C:\Users\23190\Desktop\Study\a.txt");

//b:创建BufferedInputStream对象,构造方法中传递FileInputStream对象
BufferedInputStream bis = new BufferedInputStream(fis);

byte[] b= new byte[1024];
int i = 0;
while((i=bis.read(b))!=-1){
    System.out.println(new String(b));
}

//d、释放资源
fis.close();

BufferedOutputStream 字节缓冲输出流

构造方法

  • BufferedOutputStream(OutputStream out) 创建一个新的缓冲输出流,以将数据写入指定的底层输出流。

  • BufferedOutputStream(OutputStream out, int size) 创建一个新的缓冲输出流,以便以指定的缓冲区大小将数据写入指定的底层输出流。

常用方法

  • void flush() 使用flush刷新,才会把缓冲区中的字节全部写入文件中。
  • void write(byte[] b, int off, int len) 从指定的字节数组写入 len个字节,从偏移 off开始到缓冲的输出流。
  • void write(int b) 将指定的字节写入缓冲的输出流

BufferedOutputStream的使用 🪂使用步骤:

  1. 创建字符输出流FileOutputStream对象,构造方法中绑定要输出的目的地

  2. 创建BufferedOutputStream对象,构造方法中传递FileOutputStream对象,提高FileOutputStream对象效率

  3. 使用BufferedOutputStream对象中的方法write,把数据写入到内部缓冲区中

  4. 使用BufferedOutputStream对象中的方法flush,把内部缓冲区中的数据刷新到文件中

  5. 释放资源

public static void main(String[] args) throws IOException {
    //a:创建字符输出流FileOutputStream对象,构造方法中绑定要输出的目的地
    FileOutputStream fos = new FileOutputStream("C:\Users\23190\Desktop\Study\aaa.txt");

    //b:创建BufferedOutputStream对象,构造方法中传递FileOutputStream对象,提高FileOutputStream对象效率
    BufferedOutputStream bos = new BufferedOutputStream(fos);

    //c:使用BufferedOutputStream对象中的方法write,把数据写入到内部缓冲区中
    bos.write("不喝奶茶的Programmer".getBytes());

    //  d:使用BufferedOutputStream对象中的方法flush,把内部缓冲区中的数据刷新到文件中
    bos.flush();

    //e:释放资源
    bos.close();
}

序列化与反序列化

🚦序列化是将 Java 对象转换成与平台无关的二进制流,而反序列化则是将二进制流恢复成原来的 Java 对象,二进制流便于保存到磁盘上或者在网络上传输,🚨只有实现了Serializable接口或Exteranlizable接口的类的对象才能被序列化与反序列化。Serializable是一个标记型接口,不含任何方法。

transient关键字

🚨❗ 被transient修饰的成员变量不能被序列化

  • transient只作用于实现 Serializable 接口的类的普通成员字段

  • transient只能用来修饰普通成员变量字段

  • 不管有没有transient修饰,静态变量都不能被序列化

序列化

  • java.io.ObjectOutputStream extends OutputStreamObjectOutputStream是一个处理流,实现将对象以流的方式写入到文件中保存,其序列化的实现是通过writeObject()方法将实例化对象写入到输出流中。

🛵 序列化例子

  • 先准备一个带序列化的Java类,记住必须实现Serializable接口
@Data
public class test implements Serializable {
    //序列化之后,修改成员变量,反序列化不会抛出异常
    static final long serialVersionUID = 42L;
    private String name;
    private int age;

}

🌠知识点:当我们的Java类实现Serializable时,我们会发现会自动增加一个static final long serialVersionUID = 42L成员变量,serialVersionUID是一个版本号,序列化运行时使用一个称为 serialVersionUID 的版本号与每个可序列化类相关联,该序列号在反序列化过程中用于验证序列化对象的发送者和接收者是否为该对象加载了与序列化兼容的类。如果接收者加载的该对象的类的 serialVersionUID 与对应的发送者的类的版本号不同,则反序列化将会导致 InvalidClassException。可序列化类可以通过声明名为"serialVersionUID" 的字段(该字段必须是静态 (static)、最终 (final) 的 long 型字段)显式声明其自己的 serialVersionUID(序列号)。

  • 序列化操作
public static void main(String[] args) throws IOException {
    //(1)创建ObjectOutputStream对象,构造方法中传递字节输出流FileOutputStream
    ObjectOutputStream oos =
            new ObjectOutputStream(new FileOutputStream("C:\Users\23190\Desktop\Study\aaa.txt"));

    // (2)使用ObjectOutputStream对象中的方法writeObject,把对象写入指定的文件中
    oos.writeObject(new test("不喝奶茶的Programmer",20));
    //(3)释放资源
    oos.close();
}

反序列化

java.io.ObjectInputStream extends InputStreamObjectInputStream是一个处理流,实现将对象的反序列化,其反序列化的实现是通过readObject()方法将输入流中的实例化对象读取出来。

反序列化的前提条件

  • 类必须实现Serializable

  • 必须存在类对应的.class文件

🛵 反序列化例子

  • 对以上序列化的结果进行反序列化操作
public static void main(String[] args) throws IOException, ClassNotFoundException {
    //(1)创建ObjectInputStream对象,构造方法中传递字节输入流FileInputStream
    ObjectInputStream ois = new ObjectInputStream(new FileInputStream("C:\Users\23190\Desktop\Study\aaa.txt"));

    // (2)使用ObjectInputStream对象中的方法readObject读取保存对象的文件
    Object o = ois.readObject();
    //(3)释放资源
    ois.close();
    //(4)使用读取出来的对象
    System.out.println(o.toString());//test{name='不喝奶茶的Programmer', age=20}
}

🏁以上就是对Java中IO流的简单介绍,如果有错误的地方,还请留言指正,如果觉得本文对你有帮助那就点个赞吧😻😍

默认标题_动态分割线_2021-07-15-0.gif