欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

java基础之--缓冲流-字节流+字符流+转换流+序列化+打印流

程序员文章站 2024-03-04 21:39:54
...

昨天学习了基本的一些流,作为IO流的入门,今天我们要见识一些更强大的流。比如能够高效读写的缓冲流,能够转换编码的转换流,能够持久化存储对象的序列化流等等。这些功能更为强大的流,都是在基本的流对象基础之上创建而来的,就像穿上铠甲的武士一样,相当于是对基本流对象的一种增强

1. 概述

缓冲流,也叫高效流 ,是对4个基本的FileXxx流的增强,所以也是4个流,按照数据类型分类

  • 字节缓冲流: BufferedInputStreamBufferedOutputStream
  • 字符缓冲流: BufferedReaderBufferedWriter

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

2. 字节缓冲流

构造方法

  • public BufferedInputStream(InputStream in) : 创建一个新的缓冲输入流
  • public BufferedOutputStream(OutputStream out) : 创建一个新的缓冲输出流
package Stream;

import FileStream.FileOutputStreamConstructor;

import java.io.*;

/**
 * @Description
 * @auther 宁宁小可爱
 * @create 2020-01-16 14:28
 */
public class BufferDemo {
    public static void main(String[] args) throws Exception {
        // 记录开始时间
        long startTime = System.currentTimeMillis();
        try {
            BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\softWare-all\\developSoftware\\projectPath\\java-project\\Thread\\src\\Stream\\wegameservice.exe"));
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("copy.exe"));
            int len;

            byte[] bytes = new byte[8*1024];
            while ((len = bis.read(bytes)) != -1){
                bos.write(bytes,0,len);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

        // 记录结束时间
        long endTime = System.currentTimeMillis();
        System.out.println("缓冲流使用数组复制时间: "+(endTime-startTime) + "毫秒");

    }
}

3. 字符缓冲流

  • public BufferedReader(Reader in) : 创建一个新的缓冲输入流
  • public BufferedWriter(Writer out) : 创建一个新的缓冲输出流

字符缓冲流的基本方法与普通字符流调用方式一致,不再阐述,我们来看它们具备的特有方法

  • BufferedReader: public String readLine() : 读一行文字
  • BufferedWriter: public void newLine() : 写一行行分隔符,由系统属性定义符号

readline方法演示

package Stream;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;

/**
 * @Description
 * @auther 宁宁小可爱
 * @create 2020-01-16 15:17
 */
public class BufferReaderDemo {
    public static void main(String[] args) throws Exception {
        // 创建流对象
        BufferedReader br = new BufferedReader(new FileReader("fw.txt"));

        String line = null;
        while ((line = br.readLine()) != null){
            System.out.println(line);
            System.out.println("--------------------------");
        }

        br.close();
    }
}

newLine方法演示

package Stream;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

/**
 * @Description
 * @auther 宁宁小可爱
 * @create 2020-01-16 15:20
 */
public class BufferWriterDemo {
    public static void main(String[] args) throws IOException {
        // 创建流对象
        BufferedWriter bw = new BufferedWriter(new FileWriter("fw.txt"));

        bw.write("宁宁小可爱");
        bw.newLine();
        bw.write("新年快乐");

        bw.close();
    }
}
输出结果:
宁宁小可爱
新年快乐

4. 转换流

字符集 Charset :是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等。 计算机要准确的存储和识别各种字符集符号,需要进行字符编码,一套字符集必然至少有一套字符编码。常见字符 集有ASCII字符集、GBK字符集、Unicode字符集等,可见,当指定了编码,它所对应的字符集自然就指定了,所以编码才是我们最终要关心的

java基础之--缓冲流-字节流+字符流+转换流+序列化+打印流
在IDEA中,使用 FileReader 读取项目中的文本文件。由于IDEA的设置,都是默认的 UTF-8 编码,所以没有任何问题。但是,当读取Windows系统中创建的文本文件时,由于Windows系统的默认是GBK编码,就会出现乱码,那么如何读取GBK编码的文件呢

4.1 InputStreamReader类

构造方法

  • InputStreamReader(InputStream in) : 创建一个使用默认字符集的字符流
  • InputStreamReader(InputStream in, String charsetName) : 创建一个指定字符集的字符流

指定编码读取

package Stream;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStreamReader;

/**
 * @Description
 * @auther 宁宁小可爱
 * @create 2020-01-16 15:29
 */
public class ReadDemo {
    public static void main(String[] args) throws Exception {
        String filePath = "E:\\test.txt";
        // 创建流对象
        InputStreamReader isr = new InputStreamReader(new FileInputStream(filePath));
        // 创建流对象 指定编码GBK
        InputStreamReader isr2 = new InputStreamReader(new FileInputStream(filePath));

        int read;

        while ((read = isr.read()) != -1){
            System.out.println((char)read);
        }
        isr.close();
        while ((read = isr2.read()) != -1){
            System.out.println((char)read);
        }
        isr2.close();
    }
}

输出结果: isr乱码 isr2 输出如下
新
年
快
乐
宁
宁
小
可
爱

4.2 OutputStreamWriter类

转换流 java.io.OutputStreamWriter ,是Writer的子类,是从字符流到字节流的桥梁。使用指定的字符集讲字符编码为字节。它的字符集可以由名称指定,也可以接受平台的默认字符集

构造方法

  • OutputStreamWriter(OutputStream in) : 创建一个使用默认字符集的字符流
  • OutputStreamWriter(OutputStream in, String charsetName) : 创建一个指定字符集的字符流

指定编码

package Stream;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;

/**
 * @Description
 * @auther 宁宁小可爱
 * @create 2020-01-16 15:40
 */
public class OutPutDemo {
    public static void main(String[] args) throws IOException {
        String filePath = "E:\\test.txt";
        // 创建流对象,默认UTF-8编码
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(filePath));

        // 写数据
        osw.write("宁宁小可爱");
        osw.close();


        String filePath2 = "E:\\test2.txt";
        // 创建流对象,默认UTF-8编码
        OutputStreamWriter osw2 = new OutputStreamWriter(new FileOutputStream(filePath2),"GBK");

        // 写数据
        osw2.write("宁宁小可爱");
        osw2.close();
    }
}

转换流图解

java基础之--缓冲流-字节流+字符流+转换流+序列化+打印流

5. 序列化

Java 提供了一种对象序列化的机制。用一个字节序列可以表示一个对象,该字节序列包含该对象的数据 、 对象的类型和对象中存储的数据等信息。字节序列写出到文件之后,相当于文件中持久保存了一个对象的信息。 反之,该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化。 对象的数据 、 对象的类型和对象中存储的数据信息,都可以用来在内存中创建对象

java基础之--缓冲流-字节流+字符流+转换流+序列化+打印流

5.1 ObjectOutputStream类

java.io.ObjectOutputStream 类,将Java对象的原始数据类型写出到文件,实现对象的持久存储

构造方法

  • public ObjectOutputStream(OutputStream out) : 创建一个指定OutputStream的ObjectOutputStream

序列化操作,一个对象要想序列化,必须满足两个条件

  • 该类必须实现 java.io.Serializable 接口, Serializable 是一个标记接口,不实现此接口的类将不会使任何状态序列化或反序列化,会抛出 NotSerializableException
  • 该类的所有属性必须是可序列化的。如果有一个属性不需要可序列化的,则该属性必须注明是瞬态的,使用 transient 关键字修饰
package Stream;

import sun.management.Agent;

import java.io.Serializable;

/**
 * @Description
 * @auther 宁宁小可爱
 * @create 2020-01-16 15:55
 */
public class Employee implements Serializable {
    public String name;
    public String address;
    public transient  int age; // transient瞬态修饰成员,不会被序列化
}

写出对象方法

  • public final void writeObject (Object obj) : 将指定的对象写出
package Stream;

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

/**
 * @Description
 * @auther 宁宁小可爱
 * @create 2020-01-16 15:58
 */
public class SerializeDemo {
    public static void main(String[] args)  {
        Employee e = new Employee();
        e.name = "ningning";
        e.address = "beijing";
        e.age = 19;

        try {
            ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("employee.txt"));
            out.writeObject(e);
            out.close();
            System.out.println("Serialized data is saved");
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
}

5.2 ObjectInputStream类

ObjectInputStream反序列化流,将之前使用ObjectOutputStream序列化的原始数据恢复为对象

构造方法

  • public ObjectInputStream(InputStream in) : 创建一个指定InputStream的ObjectInputStream

反序列化操作

如果能找到一个对象的class文件,我们可以进行反序列化操作,调用 ObjectInputStream 读取对象的方法

  • public final Object readObject () : 读取一个对象
package Stream;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;

/**
 * @Description
 * @auther 宁宁小可爱
 * @create 2020-01-16 16:04
 */
public class DeSerializeDemo {
    public static void main(String[] args) {
        Employee e = null;

        try {
            // 创建反序列化流
            FileInputStream fis = new FileInputStream("employee.txt");
            ObjectInputStream ois = new ObjectInputStream(fis);

            // 读取对象
            e = (Employee)ois.readObject();
            ois.close();
            fis.close();

        } catch (Exception ex) {
            ex.printStackTrace();
        }

        System.out.println("name : "+e.name);
        System.out.println("address : "+e.address);
        System.out.println("address : "+e.age);
    }
}

6. 打印流- PrintStream类

平时我们在控制台打印输出,是调用 print 方法和 println 方法完成的,这两个方法都来自于 java.io.PrintStream 类,该类能够方便地打印各种数据类型的值,是一种便捷的输出方式

构造方法

  • public PrintStream(String fileName) : 使用指定的文件名创建一个新的打印流
  • 举例如下
PrintStream ps = new PrintStream("test.txt")

改变打印流向
System.out 就是 PrintStream 类型的,只不过它的流向是系统规定的,打印在控制台上。不过,既然是流对象, 我们就可以玩一个"小把戏",改变它的流向

package Stream;

import java.io.FileNotFoundException;
import java.io.PrintStream;

/**
 * @Description
 * @auther 宁宁小可爱
 * @create 2020-01-16 16:11
 */
public class PrintDemo {
    public static void main(String[] args) throws FileNotFoundException {
        // 控制台输出 97
        System.out.println(97);
        // 创建打印流 指定文件名称
        PrintStream ps = new PrintStream("ps.txt");
        // 设置流向 输出到ps.txt
        System.setOut(ps);

        // 再次打印97
        System.out.println(97);
    }
}