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);
}
}
🔑 讲解
- OutputStreamWriter 装饰 OutputStream:
- 将字节流转换为字符流
- 可以指定字符集(Charset)
- try-with-resources 保证关闭顺序:
- 输出流和字符写入器都会在退出时自动
flush()和close() - 避免因缓冲区未刷新导致文件内容丢失
- 输出流和字符写入器都会在退出时自动
- 效果:
- 会在
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);
}
}
🔑 讲解
- InputStreamReader 装饰 InputStream:
- 将字节流转换为字符流
- BufferedReader 装饰 InputStreamReader:
- 提供按行读取功能
- 内部使用缓冲,提高读取性能
- 使用 Stream API:
BufferedReader.lines()返回Stream<String>- 结合
Collectors.joining("\n")可以轻松把所有行合并
- try-with-resources:
- 自动关闭 InputStream、Reader、BufferedReader 和 Stream
- 保证资源安全
- 效果:
- 控制台输出完整文本内容,与写入文件的内容一致
4️⃣ 小结
- OutputStreamWriter / InputStreamReader 是处理字符与字节混合 I/O 的关键工具
- 装饰者模式:
- OutputStreamReader / InputStreamReader → 装饰字节流
- BufferedReader → 进一步装饰,提供额外功能(按行读取、流式操作)
- try-with-resources 确保所有流和资源正确关闭
- 字符流与字节流组合非常灵活:
- 可用于写文本到二进制文件
- 可用于读取二进制文件中的字符