BufferedReader.readLine() 读不到最后一行是因为它只在遇到换行符(\n、\r 或 \r\n)时才返回该行内容,若文件末尾无换行符,则最后一行被缓存但未触发返回,导致下次调用返回 null。

BufferedReader.readLine() 为什么读不到最后一行?
常见现象是文件末尾没换行符时,readLine() 突然返回 null,但最后一行内容其实还没处理。这是因为 readLine() 只在遇到换行符(\n、 或 <code>\r)时才返回当前行;如果文件以文本结尾且无换行,它会把这行缓存在内部,等下次调用才返回——而你可能已经跳出循环了。
- 正确做法:循环体里每次拿到非
null的字符串就立刻处理,别假设“一定还有下一行” - 不要用
while ((line = br.readLine()) != null)后再额外 check 一次line,这个写法本身已覆盖末行 - 真正出问题的往往是手动控制循环(比如用
br.ready()判断),它不保证最后一行可读,ready()返回true也不代表readLine()不会返回null
关闭 BufferedReader 时 IOException 被吞掉怎么办?
很多人用 try-catch-finally 手动关流,但在 finally 块里调 br.close() 抛异常,又没处理,导致原始业务异常被掩盖。
- 优先用 try-with-resources:
try (BufferedReader br = new BufferedReader(new FileReader("a.txt"))) { ... },JVM 保证close()调用且异常不会干扰主流程 - 如果必须手动关,
close()的异常应单独捕获并记录(比如用log.warn("failed to close reader", e)),不能直接忽略或 throw 出去打断逻辑 -
BufferedReader.close()会级联关闭底层Reader,所以别再对FileReader单独调close()
中文乱码是不是 BufferedReader 的锅?
不是。BufferedReader 本身不负责解码,它只是缓冲层;乱码根源在底层 Reader 构造时用的字符集不对。
- 别用
new FileReader("a.txt")—— 它依赖系统默认编码(Windows 是 GBK,Linux/macOS 通常是 UTF-8),跨平台必翻车 - 显式指定编码:
new InputStreamReader(new FileInputStream("a.txt"), "UTF-8"),再包一层BufferedReader - JDK 11+ 可用
Files.newBufferedReader(Paths.get("a.txt"), StandardCharsets.UTF_8),更简洁安全 - 如果文件带 BOM,
InputStreamReader默认不跳过,需自行检测并截掉前几个字节(或用第三方库如 Apache Commons IO 的BOMInputStream)
大文件用 BufferedReader 会 OOM 吗?
一般不会。BufferedReader 默认缓冲区才 8KB,只缓存少量行;OOM 通常是因为你把所有 readLine() 结果都存进 List<string></string> 或拼成一个超长 String。
立即学习“Java免费学习笔记(深入)”;
- 按行处理就逐行处理,别 accumulate:读一行 → 解析/计算/写入 → 丢弃引用
- 如果真要全加载,确认内存够用再用
Files.readAllLines()(它内部也用BufferedReader,但会一次性分配大数组) - 缓冲区大小可调:
new BufferedReader(reader, 64 * 1024),对 SSD 或网络流有微小提升,但对普通机械硬盘或小文件意义不大
最常被忽略的是编码和资源释放——这两点出错,程序在本地跑得好好的,一上服务器或换台机器就出问题,而且错误表现还特别“随机”。










