第五知识单元

高级编程

Java程序设计 第10讲,主讲人:李欣

Created: 2023-09-12 Tue 00:42

0.1. 互动课堂

Click to host the seminar.

0.2. 签到

https://xin.blue/tool/attendance/

0.3. 本次课的目标

  • 理解 面向 字节输入输出流
  • 理解 面向 字符输入输出流
  • 了解 结点流(note stream)过滤流(filter stream)

1. 面向字节的输入输出流

1.1. InputStream

InputStream 类是 基本 输入字节流 类,是不能实例化的 抽象类

https://docs.oracle.com/en/java/javase/18/docs/api/java.base/java/io/InputStream.html

public abstract class InputStream
extends Object
implements Closeable

1.2. OutputStream

OutputStream 类是 基本 输出字节流 类,是不能实例化的 抽象类

https://docs.oracle.com/en/java/javase/18/docs/api/java.base/java/io/OutputStream.html

public abstract class OutputStream
    extends Object
    implements Closeable, Flushable

2. 面向字符的输入输出流

2.1. Reader

Reader 类是 输入字符流 类,是不能实例化的 抽象类

https://docs.oracle.com/en/java/javase/18/docs/api/java.base/java/io/Reader.html

public abstract class Reader
    extends Object
    implements Readable, Closeable

2.2. Writer

Writer 类是 输出字符流 类,是不能实例化的 抽象类

https://docs.oracle.com/en/java/javase/18/docs/api/java.base/java/io/Writer.html

public abstract class Writer
    extends Object
    implements Appendable, Closeable, Flushable

3. 结点流和过滤流

参考教材

  • 8.3.2 pp.310-311

4. 输入输出流分类关系

InputStream
 |-- FileInputStream
 |-- ByteArrayInputStream
 |-- FilterInputStream
      |-- BufferedInputStream

OutputStream
 |-- FileOutputStream
 |-- ByteArrayOutputStream
 |-- FilterOutputStream
      |-- BufferedOutputStream

Reader
 |-- InputStreamReader
      |-- FileReader
 |-- BufferedReader
 |-- StringReader

Writer
 |-- OutputStreamWriter
      |-- FileWriter
 |-- BufferedWriter
 |-- StringWriter
 |-- PrintWriter

5. 输入输出流的应用实例

5.1. InputStreamOutputStream 的派生类

5.1.1. FileInputStream FileOutputStream

import java.io.*;
public class Main {
    public static void main(String[] args) {
        byte[] readData = new byte[1024];
        // The try-with-resources Statement
        // https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html
        try ( FileInputStream fis = new FileInputStream("./input.png");
              FileOutputStream fos = new FileOutputStream("./output.png")) {
            int readBytes; // 实际读写的字节数,未接近文件末尾时为readData数组的长度
            while ((readBytes = fis.read(readData)) != -1) { // 重复读写操作,直到读取到文件末尾
                System.out.print(readBytes + " ");
                fos.write(readData, 0, readBytes);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 319 
javac Main.java
java Main
# 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 319 
javac Main.java
java Main
# 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 319 
ls -la | grep png
# -rw-r--r-- 1 x x  16703 10月 31 01:00 input.png
# -rw-rw-r-- 1 x x  16703 10月 31 01:13 output.png
javac Main.java
java Main
# 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 319 
ls -la | grep png
# -rw-r--r-- 1 x x  16703 10月 31 01:00 input.png
# -rw-rw-r-- 1 x x  16703 10月 31 01:13 output.png
md5sum input.png output.png
# 74e943d82452f81f6a0bb0b51ac6785d  input.png
# 74e943d82452f81f6a0bb0b51ac6785d  output.png
javac Main.java
java Main
# 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 319 
ls -la | grep png
# -rw-r--r-- 1 x x  16703 10月 31 01:00 input.png
# -rw-rw-r-- 1 x x  16703 10月 31 01:13 output.png
md5sum input.png output.png
# 74e943d82452f81f6a0bb0b51ac6785d  input.png
# 74e943d82452f81f6a0bb0b51ac6785d  output.png
bash -c "echo \$((703-319)) \$((24*16))"
# 384 384

java.png

Figure 1: input.png and output.png \(^{*}\)

\(*\) Java icons created by Freepik - Flaticon

5.1.2. BufferedInputStream BufferedOutputStream

import java.io.*;
public class Main {
    public static void main(String[] args) {
        byte[] readData = new byte[1024];
        try ( BufferedInputStream bis = new BufferedInputStream(new FileInputStream("./input.png"));
              BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("./output.png"))) {
            int readBytes;
            while ((readBytes = bis.read(readData)) != -1) {
                System.out.print(readBytes + " ");
                bos.write(readData, 0, readBytes);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 319 

5.2. ReaderWriter 的派生类

5.2.1. InputStreamReader OutputStreamWriter

import java.io.*;
public class Main {
    public static void main(String[] args) {
        char[] readData = new char[6];
        // ncut.txt: 北方工业大学信息学院
        try (InputStreamReader isr = new InputStreamReader(new FileInputStream("./ncut.txt"))) {
            int readChars = isr.read(readData, 0, 6); // 从第0个字符开始读取6个字符
            System.out.println(readChars); // 6
            System.out.println(new String(readData)); // 北方工业大学
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
6
北方工业大学

5.2.2. FileReader FileWriter

import java.io.*;
public class Main {
    public static void main(String[] args) {
        char[] readData = new char[6];
        // ncut.txt: 北方工业大学信息学院
        try (FileReader reader = new FileReader("./ncut.txt")) {
            int readChars = reader.read(readData, 0, 6); // 从第0个字符开始读取6个字符
            System.out.println(readChars); // 6
            System.out.println(new String(readData)); // 北方工业大学
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
6
北方工业大学

5.2.3. BufferedReader BufferedWriter

import java.io.*;
public class Main {
    public static void main(String[] args) {
        char[] readData = {'*', '*', '*', '*', '*', '*', '*', '*', '*', '*'};
        // ncut.txt: 北方工业大学信息学院
        try (BufferedReader br = new BufferedReader(new FileReader("./ncut.txt"))) {
            // 首先将充分的长度(默认是8192字符)读取到缓存
            // 之后从缓存中读取指定的字符数(这里是6字符)
            int readChars = br.read(readData, 0, 6); // 从第0个字符开始读取6个字符
            System.out.println(readChars); // 6
            System.out.println(new String(readData)); // 北方工业大学****
            // 之后从缓存中读取
            // 缓存中的数据读取完毕后则再次向缓存中一次性读取充分的长度,然后再从缓存中读取指定的字符数
            readChars = br.read(readData, readChars, 4);
            System.out.println(readChars); // 4
            System.out.println(new String(readData)); // 北方工业大学信息学院
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
6
北方工业大学****
4
北方工业大学信息学院