Java IO<3>处理流:缓冲流 数据流 转换流 对象流

Java io 处理流

节点流和处理流概述

Java流可以分节点流和处理流两类。

节点流是面向各种物理节点的流,比如面向读写文件的FileInputStream和FileOutputStream;面向对象的ObjectInputStream和ObjectOutputStream等等。

处理流则需要依附于节点流,用来对节点流的功能进行拓展和加强。比如BufferedInputStream,用它来包装FileInputStream(或者其他的节点输入流也一样)以后 ,直接调用BufferedInputStream的read方法,这个read方法的效果和FileInputStream的read方法的效果相比,就多出来一个缓存的功能。

java缓冲流本身不具IO功能,只是在别的流上加上缓冲提高效率,像是为别的流装上一种包装。当对文件或其他目标频繁读写或操作效率低,效能差。这时使用缓冲流能够更高效的读写信息。因为缓冲流先将数据缓存起来,然后一起写入或读取出来。所以说,缓冲流还是很重要的,在IO操作时记得加上缓冲流提升性能。

<1>处理流之缓冲流

缓冲流分为字节和字符缓冲流

字节缓冲流为:

BufferedInputStream—字节输入缓冲流

BufferedOutputStream—字节输出缓冲流

字符缓冲流为:

BufferedReader—字符输入缓冲流

BufferedWriter—字符输出缓冲流

BufferedWriter

    public static void main(String[] args) throws IOException {
        String filePath = "d:" + File.separator + "test.txt";
        File file = new File(filePath);
        FileWriter writer = new FileWriter(file);
        BufferedWriter bufferedWriter = new BufferedWriter(writer);
        bufferedWriter.write("c++");
        bufferedWriter.newLine();
        bufferedWriter.write("java");
        bufferedWriter.newLine();
        bufferedWriter.write(98);
        bufferedWriter.flush();
        bufferedWriter.newLine();
        char[] chars = "测试代码".toCharArray();
        bufferedWriter.write(chars, 1, chars.length - 1);
        bufferedWriter.close();
        writer.close();
/*      c++
        java
        b
        试代码*/
    }

BufferedReader

public static void main(String[] args) throws IOException {
    String filePath = "d:" + File.separator + "test.txt";
    File file = new File(filePath);
    FileReader reader = new FileReader(file);
    BufferedReader bufferedReader = new BufferedReader(reader);
    int len;
    char[] chars = new char[1024];
    String res = "";
    while ((len = bufferedReader.read(chars)) != -1) {
        res += new String(chars, 0, len);
    }
    System.out.println(res);
    bufferedReader.close();
    reader.close();
}

FileInputStream

public static void main(String[] args) throws IOException {
    String filePath = "d:" + File.separator + "test.txt";
    File file = new File(filePath);
    FileInputStream fileInputStream = new FileInputStream(file);
    BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
    int len;
    byte[] bytes = new byte[2];
    String res = "";
    while ((len = bufferedInputStream.read(bytes)) != -1) {
        res += new String(bytes, 0, len);
    }
    System.out.println(res);
    bufferedInputStream.close();
    fileInputStream.close();
}

FileOutputStream

public static void main(String[] args) throws IOException {
    String filePath = "d:" + File.separator + "test.txt";
    File file = new File(filePath);
    FileOutputStream fileOutputStream = new FileOutputStream(file);
    BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
    bufferedOutputStream.write(97);
    //换行
    bufferedOutputStream.write(10);
    byte[] bytes = "hello world".getBytes();
    bufferedOutputStream.write(bytes, 0, bytes.length - 1);
    bufferedOutputStream.close();
    fileOutputStream.close();
    //输出
    //a
    //hello worl
}

<2>处理流之转换流

转换流提供了在字节流和字符流之间的转换
Java API提供了两个转换流:

  • InputStreamReader :将InputStream 转换为Reader
  • OutputStreamWriter :将Writer 转换为OutputStream

字节流中的数据都是字符时,转成字符流操作更高效。很多时候我们使用转换流来处理文件乱码问题。实现编码和解码的功能。

InputStreamReader

实现将字节的输入流按指定字符集转换为字符的输入流。

构造器
  • public InputStreamReader(InputStream in)
  • public InputSreamReader(InputStream in,String charsetName)
    如: Reader isr = new InputStreamReader(System.in,”gbk”);

OutputStreamWriter

实现将字符的输出流按指定字符集转换为字节的输出流。

构造器
  • public OutputStreamWriter(OutputStream out)
  • public OutputSreamWriter(OutputStream out,String charsetName)
    public void testMyInput() throws Exception {
        FileInputStream fis = new FileInputStream("dbcp.txt");
        FileOutputStream fos = new FileOutputStream("dbcp5.txt");
        InputStreamReader isr = new InputStreamReader(fis, "GBK");
        OutputStreamWriter osw = new OutputStreamWriter(fos, "GBK");
        BufferedReader br = new BufferedReader(isr);
        BufferedWriter bw = new BufferedWriter(osw);
        String str = null;
        while ((str = br.readLine()) != null) {
            bw.write(str);
            bw.newLine();
            bw.flush();
        }
        bw.close();
        br.close();
    }

常见的编码表

  • ASCII:美国标准信息交换码。用一个字节的7位可以表示。
  • ISO8859-1:拉丁码表。欧洲码表,用一个字节的8位表示。
  • GB2312:中国的中文编码表。最多两个字节编码所有字符。
  • GBK:中国的中文编码表升级,融合了更多的中文文字符号。最多两个字节编码。
  • Unicode:国际标准码,融合了目前人类使用的所有字符。为每个字符分配唯一的字符码。所有的文字都用两个字节来表示。
  • UTF-8:变长的编码方式,可用1-4个字节来表示一个字符。

<3>处理流之数据流

DataOutputStream数据输出流允许应用程序将基本Java数据类型写到基础输出流中,而DataInputStream数据输入流允许应用程序以机器无关的方式从底层输入流中读取基本的Java类型.

DataInputStream

DataInputStream中的方法

public final int read(byte b[]) throws IOException {}
public final int read(byte b[], int off, int len) throws IOException {}
public final void readFully(byte b[]) throws IOException {}
public final void readFully(byte b[], int off, int len) throws IOException {}
public final int skipBytes(int n) throws IOException {}
public final boolean readBoolean() throws IOException {}
public final byte readByte() throws IOException {}
public final int readUnsignedByte() throws IOException {}
public final short readShort() throws IOException {}
public final int readUnsignedShort() throws IOException {}
public final char readChar() throws IOException {}
public final int readInt() throws IOException {}
public final long readLong() throws IOException {}
public final float readFloat() throws IOException {}
public final double readDouble() throws IOException {}
public final String readUTF() throws IOException {}

使用示例:

public static void main(String[] args) throws IOException {
    String filePath = "d:" + File.separator + "test.txt";
    File file = new File(filePath);
    FileInputStream inputStream = new FileInputStream(file);
    DataInputStream dataInputStream = new DataInputStream(inputStream);
    char c = dataInputStream.readChar();
    String s = dataInputStream.readUTF();
    float v = dataInputStream.readFloat();
    System.out.println(c);
    System.out.println(s);
    System.out.println(v);
}

DataOutputStream

DataOutputStream中的方法:

private void incCount(int value) {}
public synchronized void write(int b) throws IOException {}
public synchronized void write(byte b[], int off, int len) throws IOException {}
public void flush() throws IOException {}
public final void writeBoolean(boolean v) throws IOException {}
public final void writeByte(int v) throws IOException {}
public final void writeShort(int v) throws IOException {}
public final void writeChar(int v) throws IOException {}
public final void writeInt(int v) throws IOException {}
public final void writeLong(long v) throws IOException {}
public final void writeFloat(float v) throws IOException {}
public final void writeDouble(double v) throws IOException {}
public final void writeBytes(String s) throws IOException {}
public final void writeChars(String s) throws IOException {}
public final void writeUTF(String str) throws IOException {}
public final int size() {}

使用示例:

public static void main(String[] args) throws IOException {
    String filePath = "d:" + File.separator + "test.txt";
    File file = new File(filePath);
    FileOutputStream outputStream = new FileOutputStream(file);
    DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
    dataOutputStream.writeUTF("hello");
    dataOutputStream.write(97);
    dataOutputStream.writeChars("\n");
    dataOutputStream.writeBoolean(true);
    dataOutputStream.writeChar(10);
    dataOutputStream.writeDouble(7.62);
    dataOutputStream.flush();
    dataOutputStream.close();
    outputStream.close();
}

<4>处理流之对象流

ObjectInputStream 和OjbectOutputSteam用于存储和读取基本数据类型数据或 对象的处理流。它的强大之处就是可以把Java中的对象写入到数据源中,也能把对象从数据源中还原回来。

  • 序列化:用ObjectOutputStream类 保存基本类型数据或对象的机制
  • 反序列化:用ObjectInputStream类 读取基本类型数据或对象的机制
  • ObjectOutputStream和ObjectInputStream不能序列化static和transient修饰的成员变量
序列化

对象序列化机制允许把内存中的Java对象转换成平台无关的二进制流,从
而允许把这种二进制流持久地保存在磁盘上,或通过网络将这种二进制流传
输到另一个网络节点。当其它程序获取了这种二进制流,就可以恢复成原
来的Java对象。
序列化的好处在于可将任何实现了Serializable接口的对象转化为 字节数据,
使其在保存和传输时可被还原。序列化是 RMI(Remote Method Invoke – 远程方法调用)过程的参数和返回值都必须实现的机制,而 RMI 是 JavaEE 的基础。因此序列化机制是JavaEE 平台的基础。如果需要让某个对象支持序列化机制,则必须让对象所属的类及其属性是可序列化的,为了让某个类是可序列化的,该类必须实现如下两个接口之一。否则,会抛出NotSerializableException异常。

  • Serializable
  • Externalizable

实现了Serializable 接口的对象,可将它们转换成一系列字节,并可在以后
完全恢复回原来的样子。 这一过程亦可通过网络进行。这意味着序列化机
制能自动补偿操作系统间的差异。在 换句话说,可以先在Windows 机器上创
台 建一个对象,对其序列化,然后通过网络发给一台Unix 机器,然后在那里
准确无误地重新“装配”。不必关心数据在不同机器上如何表示,也不必
关心字节的顺序或者其他任何细节。

凡是实现Serializable接口的类都有一个表示序列化版本标识符的静态变量:
private static final long serialVersionUID;
serialVersionUID用来表明类的不同版本间的兼容性。 简言之,其目的是以序列化对象进行版本控制,有关各版本反序列化时是否兼容。
如果类没有显示定义这个静态常量,它的值是Java运行时环境根据类的内部细节自动生成的。若类的实例变量做了修改,serialVersionUID 可能发生变化。故建议,显式声明
简单来说,Java的序列化机制是通过在运行时判断类的serialVersionUID来验
证版本一致性的。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体类的serialVersionUID进行比较,如果相同
就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异
常。(InvalidCastException)

使用对象流序列化对象

若某个类实现了 Serializable 接口,该类的对象就是可序列化的:
创建一个 ObjectOutputStream, 调用 ObjectOutputStream 对象的 writeObject( 对象) 方法输出可 序列化对象,注意写出一次,操作flush() 一次。
反序列化,创建一个 ObjectInputStream, 调用 readObject() 方法读取流中的对象。
如果某个类的属性不是基本数据类型或 String 类型,而是另一个
引用类型,那么这个引用类型必须是可序列化的,否则拥有该类型的
Field 的类也不能序列化

示例:

public static void main(String[] args) throws IOException, ClassNotFoundException {
    String filePath = "d:" + File.separator + "test.txt";
    File file = new File(filePath);
    InputStream inputStream = new FileInputStream(file);
    OutputStream outputStream = new FileOutputStream(file);
    ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
    Person lilei = new Person("李雷", 25, 1.78, true, 58);
    objectOutputStream.writeObject(lilei);
    objectOutputStream.flush();
    objectOutputStream.close();
    ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
    Person p = (Person) objectInputStream.readObject();
    System.out.println(p);
    objectInputStream.close();
    //Person{name='李雷', age=25, height=1.78, isMale=true, weight=58.0}
}

Person类:

import java.io.Serializable;
public class Person implements Serializable {
    public String name;
    public int age;
    public double height;
    public boolean isMale;
    public double weight;

    public Person(String name, int age, double height, boolean isMale, double weight) {
        this.name = name;
        this.age = age;
        this.height = height;
        this.isMale = isMale;
        this.weight = weight;
    }
    
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", height=" + height +
                ", isMale=" + isMale +
                ", weight=" + weight +
                '}';
    }
}

<5>处理流之标准输入输出流

System.in和System.out分别代表了系统标准的输入和输出设备
默认输入设备是:键盘,输出设备是:显示器
System.in的类型是InputStream
System.out的类型是PrintStream,其是OutputStream的子类

public static void main(String[] args) throws IOException, ClassNotFoundException {
    System.out.println("请输入信息(退出输入e或exit):");
    // 把"标准"输入流(键盘输入)这个字节流包装成字符流,再包装成缓冲流
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    String s = null;
    try {
        while ((s = br.readLine()) != null) { // 读取用户输入的一行数据 --> 阻塞程序
            if ("e".equalsIgnoreCase(s) || "exit".equalsIgnoreCase(s)) {
                System.out.println("安全退出!!");
                break;
            }
            System.out.println("-->:" + s.toUpperCase());
            System.out.println("继续输入信息");
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        try {
            if (br != null) {
                br.close(); // 关闭过滤流时,会自动关闭它包装的底层节点流
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
posted @ 2022-04-02 15:54  aixueforever  阅读(134)  评论(0编辑  收藏  举报