21 Java 中的缓冲流、转换流、序列化流、打印流

缓冲流、转换流、序列化流、打印流

一、缓冲流

1. 缓冲流的原理

2. BufferedOutputStream字节缓冲输出流

  • java.io.BufferedOutputStream extends OutputStream
  • BufferedOutputStream 字节缓冲输出流。
  • 继承自父类的共性成员方法:
    • public void close():关闭此输出流并释放与此流相关联的任何系统资源。
    • public void flush():刷新此输出流并强制任何缓冲的输出字节被写出。
    • public void write(byte[] b):将b.length字节从指定的字节数组写入此输出流。
    • public void write(byte[] b, int off, int len):从指定的字节数组写入len字节,从偏移量off开始输出到此输出流。
    • public abstract void write(int b):将指定的字节输出流。
  • 构造方法:
    • BufferedOutputStream(OutputStream out):创建一个新的缓冲输出流,以将数据写入指定的底层输出流。
    • BufferedOutputStream(OutputStream out, int size):创建一个新的缓冲输出流,以将具有指定缓冲区大小的数据写入指定的底层输出流。
    • 参数:
      • OutputStream out:字节输出流。可以传递FileOutputStream,缓冲流会给FileOutputStream增加一个缓冲区,提高FileOutputStream的写入效率。
      • int size:指定缓冲流内部缓冲区的大小,不指定采用默认。
  • 使用步骤:
    • 创建FileOutputStream对象,构造方法中绑定要输出的目的地。
    • 创建BufferedOutputStream对象,构造方法中传递FileOutputStream对象,提高FileOutputStream对象效率。
    • 使用BufferedOutputStream对象中的方法write,把数据写入到内部缓冲区中。
    • 使用BufferedOutputStream对象中的方法flush,把内部缓冲区中的数据,刷新到文件中。
    • 释放资源(close方法会先调用flush方法刷新数据)。
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class Test {
    public static void main(String[] args) throws IOException {
        FileOutputStream fos = new FileOutputStream("/Users/zgl/Desktop/a.txt");
        BufferedOutputStream bos = new BufferedOutputStream(fos);
        bos.write("zhuguli".getBytes());
        bos.flush();
        bos.close();
    }
}

3. BufferedInputStream字节缓冲输入流

  • java.io.BufferedInputStream extends InputStream

  • BufferedInputStream字节缓冲输入流。

  • 继承自父类的成员方法:

    • int read():从输入流中读取数据的下一个字节并返回,读取到文件的末尾返回-1。
    • int read(byte[] b):从输入流中读取一定数量的字节,并将其存储在缓冲区的数组b中。
    • void close():关闭此输入流并释放与该流关联的所有系统资源。
  • 构造方法:

    • BufferedInputStream(InputStream in):创建一个BufferedInputStream对象,并保存其参数,即输入流in,以便将来使用。
    • BufferedInputStream(InputStream in, int size):创建具有指定缓冲区大小的BufferedInputStream并保存其参数,即输入流in,以便将来使用。
    • 参数:
      • InputStream in:字节输入流,可以传递FileInputStream,缓冲流会给FileInputStream增加一个缓冲区,提高FileInputStream的读取效率。
      • int size:指定缓冲流内部缓冲区的大小,不指定默认。
  • 使用步骤:

    • 创建FileInputStream对象,构造方法中绑定要读取的数据源。
    • 创建BufferedInputStream对象,构造方法中传递FileInputStream对象,提高FileInputStream对象读取效率。
    • 使用BufferedInputStream对象中的方法read,读取文件。
    • 释放资源。
    import java.io.BufferedInputStream;
    import java.io.FileInputStream;
    import java.io.IOException;
    
    public class Test {
        public static void main(String[] args) throws IOException {
            FileInputStream fis = new FileInputStream("/Users/zgl/Desktop/a.txt");
            BufferedInputStream bis = new BufferedInputStream(fis);
    
            /*int tmp;
            while ((tmp = bis.read()) != -1) {
                System.out.print((char)tmp);
            }*/
    
            byte[] bytes = new byte[1024];
            int len;
            while ((len = bis.read(bytes)) != -1) {
                System.out.println(new String(bytes,0,len));
            }
            
            bis.close();
        }
    }
    

4. BufferedWriter字符缓冲输出流

  • java.io.BufferedWriter extends Writer
  • BufferedWriter字符缓冲输出流。
  • 继承自父类的共性成员方法:
    • 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为写的字符个数。
    • void flush():刷新该流的缓冲。
    • void close():关闭此流,但要先刷新它。
  • 构造方法:
    • BufferedWriter(Writer out):创建一个使用默认大小输出缓冲区的缓冲字符输出流。
    • BufferedWriter(Writer out, int size):创建一个人使用给定大小缓冲区的新缓冲字符输出流。
    • 参数:
      • Writer out:字符输出流,可以传递FileWriter,缓冲流会给FileWriter增加一个缓冲区,提高FileWriter的写入效率。
      • int size:指定缓冲区的大小,不写采用默认大小。
  • 特有的成员方法:void newLine()写入一个换行符。
  • 使用步骤:
    • 创建字符缓冲输出流对象,构造方法中传递字符输出流。
    • 调用字符缓冲输出流中的方法write,把数据写入到内存缓冲区中。
    • 调用字符缓冲输出流中的方法flush,把内存缓冲区中的数据刷新到文件中。
    • 释放资源。
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

public class Test {
    public static void main(String[] args) throws IOException {
        FileWriter fw = new FileWriter("/Users/zgl/Desktop/b.txt");
        BufferedWriter bw = new BufferedWriter(fw);
        for (int i = 0; i < 5; i++) {
            bw.write("朱古力");
            bw.newLine();
        }
        bw.flush();
        bw.close();
    }
}

5. BufferedRead字符缓冲输入流

  • java.io.BufferedReader extends Reader
  • 继承自父类的共性成员方法:
    • int read():读取单个字符并返回。
    • int read(char[] cbuf):一次读取多个字符,将字符读入数组。
    • void close():关闭该流并释放与之关联的所有资源。
  • 构造方法:
    • BufferedRead(Reader in):创建一个使用默认大小输入缓冲区的缓冲字符输入流。
    • BufferedRead(Reader in, int size):创建一个使用指定大小输入缓冲区的缓冲字符输入流。
    • 参数:
      • Reader in:字符输入流,可以传递FileReader,缓冲流会给FileReader增加一个缓冲区,提高FileReader的读取效率。
  • 特有的成员方法:String readline()读取一个文本行,读取一行数据。
    • 行的终止符号:通过下列字符之一即可认为某行已终止:\n\r\r\n
    • 返回值:包含该行内容的字符串,不包含任何行终止符。如果已到达流末尾,则返回null
  • 使用步骤:
    • 创建字符缓冲输入流对象,构造方法中传递字符输入流。
    • 使用字符缓冲输入流对象中的方法read/readLine读取文本。
    • 释放资源。
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class Test {
    public static void main(String[] args) throws IOException {
        FileReader fr = new FileReader("/Users/zgl/Desktop/b.txt");
        BufferedReader br = new BufferedReader(fr);
        String line;
        while ((line = br.readLine()) != null) {
            System.out.println(line);
        }
        br.close();
    }
}

二、转换流

1. OutputStreamWriter

  • java.io.OutputStreamWriter extends Writer
  • OutputStreamWriter:是字符流通向字节流的桥梁,可以使用指定的charset将要写入流中的字符编码成字节。
  • 继承自父类的共性成员方法:
    • 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为写的字符个数。
    • void flush():刷新该流的缓冲。
    • void close():关闭此流,但要先刷新它。
  • 构造方法:
    • OutputStreamWriter(OutputStream out):创建使用默认字符编码的OutputStreamWriter
    • OutputStreamWriter(OutputStream out, String charsetName):创建使用指定字符集的OutputStreamWriter
    • 参数:
      • OutputStream out:字节输出流,可以用来写转换之后的字节到文件中。
      • String charsetName:指定的编码表名称,不区分大小写,可以是utf-8UTF-8gbkGBK…不指定默认使用UTF-8
  • 使用步骤:
    • 创建OutputStreamWriter对象,构造方法中传递字节输出流和指定的编码表名称。
    • 使用OutputStreamWriter对象中的方法write,把字符转换为字节存储到缓冲区中。
    • 使用OutputStreamWriter对象中的方法flush,把内存缓冲区中的字节刷新到文件中。
    • 释放资源。
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;

public class Test {
    public static void main(String[] args) throws IOException {
        write_utf_8();
        write_gbk();
    }

    private static void write_gbk() throws IOException {
        OutputStreamWriter osw = new OutputStreamWriter(new 	FileOutputStream("/Users/zgl/Desktop/gbk.txt"), "gbk");
        osw.write("你好");
        osw.flush();
        osw.close();
    }

    private static void write_utf_8() throws IOException {
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("/Users/zgl/Desktop/utf_8.txt"), "utf-8");
        osw.write("你好");
        osw.flush();
        osw.close();
    }
}

2. InputStreamReader

  • java.io.InputStreamReader extends Reader
  • InputStreamReader:是字节流通向字符流的桥梁,它是由指定的charset读取字节并将其解码为字符。
  • 继承自父类的共性成员方法:
    • int read():读取单个字符并返回。
    • int read(char[] cbuf):一次读取多个字符,将字符读入数组。
    • void close():关闭该流并释放与之关联的所有资源。
  • 构造方法:
    • InputStreamReader(InputStream in):创建一个使用默认字符集的InputStreamReader
    • InputStreamReader(InputStream in, String charsetName):创建使用指定字符集的InputStreamReader
    • 参数:
      • InputStream in:字节输入流,用来读取文件中保存的字节。
      • String charsetName:指定的编码表名称,不区分大小写,可以是utf-8UTF-8gbkGBK…不指定默认使用UTF-8
  • 使用步骤:
    • 创建InputStreamReader对象,构造方法中传递字节输入流和指定的编码表名称。
    • 使用InputStreamReader对象中的方法read读取文件。
    • 释放资源。
  • 注意事项:构造方法中指定的编码表名称要和文件的编码相同,否则会发生乱码。
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

public class Test {
    public static void main(String[] args) throws IOException {
        read_utf_8();
        read_gbk();
    }

    private static void read_gbk() throws IOException {
        InputStreamReader isr = new InputStreamReader(new FileInputStream("/Users/zgl/Desktop/gbk.txt"),
                "gbk");
        int tmp;
        while ((tmp = isr.read()) != -1) {
            System.out.println((char) tmp);
        }
        isr.close();
    }

    private static void read_utf_8() throws IOException {
        InputStreamReader isr = new InputStreamReader(new FileInputStream("/Users/zgl/Desktop/utf_8.txt"),
                                                "utf-8");
        int tmp;
        while ((tmp = isr.read()) != -1) {
            System.out.println((char) tmp);
        }
        isr.close();
    }
}

三、序列化流

1. 序列化与反序列化的概述

  • 序列化:把对象以流的方式,写入到文件中保存,叫写对象,也叫对象的序列化。
    • 对象中包含的不仅仅是字符,使用字节流。
    • ObjectOutputStream:对象的序列化流。
  • 反序列化:把文件中保存的对象,以流的方式读取出来,叫读对象,也叫对象的反序列化。
    • 读取的文件保存的都是字节,使用字节流。
    • ObjectInputStream:对象的反序列化流。

2. 对象的序列化流

  • java.io.ObjectOutputStream extends OutputStream
  • 序列化和反序列化的时候,会抛出NotSerializableException没有序列化异常。
    • 类通过实现java.io.Serializable接口已启用其序列化功能,未实现此接口的类将无法使其任何状态序列化或反序列化。
    • Serializable接口也叫标记型接口。
    • 要进行序列化或反序列化的类必须实现Serializable接口,就会给类添加一个标记。
    • 当我们进行序列化或反序列化的时候,就会检测类上是否有这个标记。
      • 有:可以进行序列化或反序列化。
      • 没有:就会抛出NotSerializableException没有序列化异常。
  • ObjectOutputStream:对象的序列化流。
  • 作用:把对象以流的方式写入到文件中保存。
  • 构造方法:ObjectOutputStream(OutputStream out):创建写入指定OutputStreamObjectOutputStream
    • 参数:
      • OutputStream out:字节输出流。
  • 特有的成员方法:void writeObject(Object obj)将指定的对象写入ObjectOutputStream
  • 使用步骤:
    • 创建ObjectOutputStream对象,构造方法中传递字节输出流。
    • 使用ObjectOutputStream对象中的方法writeObject,把对象写入到文件中。
    • 释放资源。
import java.io.Serializable;

public class Person implements Serializable {
    private String name;
    private int age;

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

public class Test {
    public static void main(String[] args) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("/Users/zgl/Desktop/person.txt"));
        oos.writeObject(new Person("zhuguli",18));
        oos.close();
    }
}

3. 对象的反序列化流

  • java.io.ObjectInputStream extends InputStream
  • ObjectInputStream 对象的反序列化流。
  • 作用:把文件中保存的对象,以流的方式读取出来使用。
  • 构造方法:ObjectInputStream(InputStream in)创建从指定InputStream读取的ObjectInputStream
    • 参数:InputStream in字节输入流
  • 特有的成员方法:Object readObject()ObjectInputStream读取对象。
    • 该方法声明抛出了ClassNotFoundException异常,当不存在对象的class文件时抛出此异常。
  • 反序列化的前提:
    • 类必须实现Serializable接口。
    • 必须存在类对应的class文件。
  • 使用步骤:
    • 创建ObjectInputStream对象,构造方法中传递字节输入流。
    • 使用ObjectInputStream对象中的方法readObject读取保存对象的文件。
    • 释放资源。
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;

public class Test {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("/Users/zgl/Desktop/person.txt"));
        Object o = ois.readObject();
        ois.close();
        System.out.println(o);   // Person{name='zhuguli', age=18}
    }
}

4. 瞬态关键字

  • static关键字
    • 静态优先于非静态加载到内存中(静态优先于对象进入到内存中)。
    • static修饰的成员变量是不能被序列化的,序列化的都是对象。
  • transient关键字:瞬态关键字
    • transient修饰的成员变量是不能被序列化的。

5. 反序列化的InvalidClassException异常

  • 每次修改类的定义,都会给class文件生成一个新的序列号。

  • 可以在类中声明名为serialVersionUID的字段。

    • 格式:static final long serialVersionUID = xL;

      import java.io.Serializable;
      
      public class Person implements Serializable {
        
          static final long serialVersionUID = 42L;
        
          private String name;
          private int age;
      
          public Person() {
          }
      
          public Person(String name, int age) {
              this.name = name;
              this.age = age;
          }
      
          @Override
          public String toString() {
              return "Person{" +
                      "name='" + name + '\'' +
                      ", age=" + age +
                      '}';
          }
      
          public String getName() {
              return name;
          }
      
          public void setName(String name) {
              this.name = name;
          }
      
          public int getAge() {
              return age;
          }
      
          public void setAge(int age) {
              this.age = age;
          }
      }
      

四、打印流

  • java.io.PrintStream打印流
  • 特点:
    • 只负责数据的输出,不负责数据的读取。
      • 与其他输出流不同,PrintStream永远不会抛出IOException
      • 有特有的方法:print,println
  • 构造方法:
    • PrintStream(File file):输出的目的地是一个文件。
    • PrintStream(OutputStream out):输出的目的地是一个字节输出流。
    • PrintStream(String filename):输出的目的地是一个文件路径。
  • PrintStream extends OutputStream
    • 继承自父类的方法:
      • public void close():关闭此输出流并释放与此流相关联的任何系统资源。
      • public void flush():刷新此输出流并强制任何缓冲的输出字节被写出。
      • public void write(byte[] b):将b.length字节从指定的字节数组写入此输出流。
      • public void write(byte[] b, int off, int len):从指定的字节数组写入len字节,从偏移量off开始输出到此输出流。
      • public abstract void write(int b):将指定的字节输出流。
  • 注意:
    • 如果使用继承自父类的write方法写数据,那么查看数据的时候会查询编码表。
    • 如果使用自己特有的print\println方法写数据,写的数据原样输出。
import java.io.FileNotFoundException;
import java.io.PrintStream;

public class Test {
    public static void main(String[] args) throws FileNotFoundException {
        PrintStream ps = new PrintStream("/Users/zgl/Desktop/print.txt");
        ps.write(97);
        ps.println(97);
        ps.close();
    }
}
  • 可以改变输出语句的目的地(打印流的流向)。

  • 使用System.setOut方法改变输出语句的目的地改为参数中传递的打印流的目的地。

    • static void setOut(PrintStream out)重新分配”标准“输出流。
    import java.io.FileNotFoundException;
    import java.io.PrintStream;
    
    public class Test {
        public static void main(String[] args) throws FileNotFoundException {
            System.out.println("控制台输出");
            System.setOut(new PrintStream("/Users/zgl/Desktop/test.txt"));
            System.out.println("文件中输出");
        }
    }
    
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值