290. Java Stream API - 从文本文件的行创建 Stream
🎯 核心概念
在 Java 中,能够直接打开一个文本文件并对其进行流式处理是一种非常强大的模式。
- 传统方式:
Java I/O API提供了通过BufferedReader.readLine()方法逐行读取文件内容的方式。这需要使用循环逐行读取文件并处理每一行。 Stream API的优势: 使用Stream API,你可以更简洁、更具可维护性地处理文件内容,代码可读性更高。
📌 创建流的两种模式
- 基于现有的
BufferedReader: 如果你需要重构已经使用BufferedReader的代码,可以使用BufferedReader.lines()方法来获取一个行流。 - 基于新代码: 如果你是编写新代码来处理文件内容,建议使用
Files.lines()方法。这个方法接收一个Path参数,并且有一个重载版本,允许你指定字符集(Charset),以支持读取非UTF-8编码的文件。
📌 文件流的关闭
重要概念: 处理文件时,文件资源必须在不再需要时关闭,以释放系统资源。幸运的是,Stream 接口实现了 AutoCloseable 接口,这意味着你可以通过 try-with-resources 语法自动关闭文件流。
这样,Stream 本身作为一个资源,可以在你使用完后自动调用 close() 方法进行关闭。这对于 I/O 操作至关重要,因为没有正确关闭文件流,可能会导致资源泄漏。
📌 示例:统计日志文件中的警告数量
以下是一个通过 Stream API 统计日志文件中警告数量的示例。由于某些环境限制,你无法直接在浏览器中运行此代码。你可以将其复制到本地的 IDE 中,并调整文件路径来运行。
java
Path log = Path.of("/tmp/debug.log"); // 根据本地文件路径调整
try (Stream<String> lines = Files.lines(log)) { // 使用 try-with-resources 确保文件流关闭
long warnings =
lines.filter(line -> line.contains("WARNING")) // 过滤出包含 "WARNING" 的行
.count(); // 统计行数
System.out.println("Number of warnings = " + warnings); // 输出结果
} catch (IOException e) { // 处理可能的异常
// 这里可以处理异常,比如打印日志等
e.printStackTrace();
}
🧾 输出示例:
java
Number of warnings = 15
🧠 讲解:
Files.lines(log):此方法返回一个包含文件中所有行的Stream<String>。你可以对这个流执行操作。lines.filter(line -> line.contains("WARNING")):过滤出所有包含 "WARNING" 关键字的行。count():统计符合条件的行数。try-with-resources:Stream是一个资源,try-with-resources会自动在结束时关闭它,避免资源泄露。
📚 小贴士
- 字符集处理: 如果文件是非
UTF-8编码,你可以使用Files.lines(path, Charset)来读取该文件。 - 异常处理: 处理文件流时,通常会遇到
IOException,因此需要进行异常捕获和处理。
🎯 小测验(课堂互动)
问题: 如果在文件中查找 "ERROR" 关键字,如何修改过滤条件?
✅ A. lines.filter(line -> line.contains("ERROR")) ❌ B. lines.filter(line -> line.contains("WARNING")) ✅ 正确答案: A
📌 总结
Files.lines()和BufferedReader.lines()都是处理文本文件行的优秀方式。try-with-resources是处理 I/O 流的最佳实践,它确保了文件流的正确关闭。- 使用
Stream API可以使文件处理的代码更加简洁、可读和可维护。