files.lines()必须用try-with-resources显式关闭,否则文件句柄泄露易致“too many open files”;正确写法是将stream声明在try括号内,确保异常或正常退出时自动调用close()释放资源。

<p>使用 <code>Files.lines()</code> 时必须配合 try-with-resources,否则底层的 <code>Stream</code> 不会自动关闭,文件句柄将长期占用,尤其在读取大文件时容易触发“Too many open files”异常。</p> <h3>为什么 Files.lines() 需要显式关闭</h3> <p><code>Files.lines(Path)</code> 返回的是一个 <code>Stream<String></code>,但它背后封装了 <code>BufferedReader</code> 和底层文件通道。这个流是“可关闭的(closeable)”,但 Java 的 <code>Stream</code> 默认不会自动关闭——除非你用 try-with-resources 显式声明它为资源。</p> <p>若仅写:<br><font color="red"><code>Stream<String> lines = Files.lines(path);</code></font><br> 即使后续调用了 <code>lines.forEach(...)</code> 或 <code>lines.count()</code>,流也不会自动关闭,句柄泄露风险极高。</p> <h3>正确写法:try-with-resources 包裹 Stream</h3> <p>把 <code>Stream</code> 声明在 try 括号内,JVM 会在 try 块退出(无论正常还是异常)时自动调用其 <code>close()</code> 方法:</p>
- ✅ 正确示例:
try (Stream<String> lines = Files.lines(Paths.get("large.log"))) {<br>
lines.filter(line -> line.contains("ERROR"))<br>
.limit(10)<br>
.forEach(System.out::println);<br>
} catch (IOException e) {<br>
e.printStackTrace();<br>
}
此时即使中间抛出异常或提前 return,lines.close() 仍会被调用,释放文件句柄和缓冲区。
常见错误与注意事项
- ❌ 不要把 stream 赋值给变量再在 try 外使用(破坏资源生命周期);
- ❌ 不要用
stream.iterator()或stream.spliterator()后丢弃 stream 引用——关闭责任仍在 stream 上; - ⚠️ 若需多次遍历,不能复用同一 stream(已关闭或已消费),应重新调用
Files.lines(); - ✅ 支持指定字符集:
Files.lines(path, StandardCharsets.UTF_8),避免平台默认编码问题。
替代方案:何时考虑 BufferedReader
如果逻辑复杂(如需要标记、回退、逐行状态维护),或者想更明确控制关闭时机,可直接用 BufferedReader + try-with-resources:
try (BufferedReader reader = Files.newBufferedReader(Paths.get("data.txt"))) {<br>
String line;<br>
while ((line = reader.readLine()) != null) {<br>
// 处理 line<br>
}<br>
}
这种方式语义更清晰,且无需担心 Stream 中间操作的关闭陷阱,适合对资源控制要求极高的场景。










