406. Java 文件操作基础 - 字符与二进制流

19 阅读2分钟

406. Java 文件操作基础 - 字符与二进制流

1️⃣ 概述

在 Java I/O API 中,类分为两大类:

  • 字符流(Reader / Writer):处理文本数据
  • 字节流(InputStream / OutputStream):处理二进制数据

虽然字符流通常用于文本文件,但在应用程序中也常需要将字符写入二进制文件。 Java 提供了两个关键类来实现这一点:

  • InputStreamReader:从字节流读取字符
  • OutputStreamWriter:向字节流写入字符

这两个类都是 装饰器(Decorator)模式 的例子,它们依赖底层的字节流,并提供字符处理功能。


2️⃣ Writing Characters using OutputStreamWriter

import java.nio.file.*;
import java.io.*;

public class WriteCharToBinary {
    public static void main(String[] args) throws IOException {
        String message = "From fairest creatures we desire increase,\n" +
                "That thereby beauty's rose might never die,\n" +
                "But as the riper should by time decease\n" +
                "His tender heir might bear his memory:\n" +
                "But thou, contracted to thine own bright eyes,\n" +
                "Feed'st thy light's flame with self-substantial fuel,\n" +
                "Making a famine where abundance lies,\n" +
                "Thyself thy foe, to thy sweet self too cruel.\n" +
                "Thou that art now the world's fresh ornament,\n" +
                "And only herald to the gaudy spring,\n" +
                "Within thine own bud buriest thy content,\n" +
                "And, tender churl, mak'st waste in niggardly.\n" +
                "Pity the world, or else this glutton be,\n" +
                "To eat the world's due, by the grave and thee.";

        Path path = Paths.get("sonnet.txt");

        try (OutputStream outputStream = Files.newOutputStream(path);
             OutputStreamWriter writer = new OutputStreamWriter(outputStream, "UTF-8")) {

            writer.write(message);

        } catch (IOException e) {
            e.printStackTrace();
        }

        long size = Files.size(path);
        System.out.println("size = " + size);
    }
}

🔑 讲解

  1. OutputStreamWriter 装饰 OutputStream
    • 将字节流转换为字符流
    • 可以指定字符集(Charset)
  2. try-with-resources 保证关闭顺序
    • 输出流和字符写入器都会在退出时自动 flush()close()
    • 避免因缓冲区未刷新导致文件内容丢失
  3. 效果
    • 会在 files/sonnet.txt 创建一个文本文件
    • 控制台输出文件大小,例如:size = 609

3️⃣ Reading Characters using InputStreamReader

import java.nio.file.*;
import java.io.*;
import java.util.stream.*;
import java.util.*;

public class ReadCharFromBinary {
    public static void main(String[] args) {
        Path path = Path.of("files/sonnet.txt");
        String sonnet = null;

        try (InputStream inputStream = Files.newInputStream(path);
             InputStreamReader reader = new InputStreamReader(inputStream);
             BufferedReader bufferedReader = new BufferedReader(reader);
             Stream<String> lines = bufferedReader.lines()) {

            // 使用流将每行文本合并为一个完整字符串
            sonnet = lines.collect(Collectors.joining("\n"));

        } catch (IOException e) {
            e.printStackTrace();
        }

        System.out.println("sonnet = \n" + sonnet);
    }
}

🔑 讲解

  1. InputStreamReader 装饰 InputStream
    • 将字节流转换为字符流
  2. BufferedReader 装饰 InputStreamReader
    • 提供按行读取功能
    • 内部使用缓冲,提高读取性能
  3. 使用 Stream API
    • BufferedReader.lines() 返回 Stream<String>
    • 结合 Collectors.joining("\n") 可以轻松把所有行合并
  4. try-with-resources
    • 自动关闭 InputStream、Reader、BufferedReader 和 Stream
    • 保证资源安全
  5. 效果
    • 控制台输出完整文本内容,与写入文件的内容一致

4️⃣ 小结

  • OutputStreamWriter / InputStreamReader 是处理字符与字节混合 I/O 的关键工具
  • 装饰者模式
    • OutputStreamReader / InputStreamReader → 装饰字节流
    • BufferedReader → 进一步装饰,提供额外功能(按行读取、流式操作)
  • try-with-resources 确保所有流和资源正确关闭
  • 字符流与字节流组合非常灵活:
    • 可用于写文本到二进制文件
    • 可用于读取二进制文件中的字符