Files.readAllLines() 返回的 List 每行末尾无换行符,因其底层调用 BufferedReader.readLine() 默认剥离 \n、\r\n 或 \r;需拼接回原文时应手动添加换行符,并显式指定编码(如 StandardCharsets.UTF_8)避免乱码,大文件慎用以防 OOM,路径异常需提前用 Files.exists() 和 Files.isReadable() 校验。

Files.readAllLines() 读取文件后,为什么返回的 List 每行末尾没有换行符?
因为 Files.readAllLines() 的设计就是按“逻辑行”切分:它用 BufferedReader.readLine() 底层实现,而该方法默认剥离了 \n、\r\n 或 \r。所以你拿到的是干净的字符串列表,每项不带换行符——这是预期行为,不是 bug。
如果你后续要拼接回原始文本(比如写回文件),得自己补:String.join("\n", lines),注意换行符需按目标平台选(Windows 用 "\r\n")。
中文乱码或特殊字符出错,该怎么指定编码?
不传编码时,默认用 StandardCharsets.UTF_8(Java 11+),但老版本(如 Java 8)会用 Charset.defaultCharset(),这依赖系统环境,极容易在 Linux 服务器上读 Windows 生成的 GBK 文件时崩出 MalformedInputException。
务必显式传入编码:
立即学习“Java免费学习笔记(深入)”;
List<String> lines = Files.readAllLines(Paths.get("data.txt"), StandardCharsets.UTF_8);
// 或 GBK(慎用,仅限遗留系统)
List<String> lines = Files.readAllLines(Paths.get("log.txt"), Charset.forName("GBK"));
- 优先用
StandardCharsets中的常量,避免字符串拼错 - 不要依赖
defaultCharset(),CI/CD 环境和本地开发机编码常不一致 - 若不确定源文件编码,先用
file -i filename(Linux/macOS)或 VS Code 编码检测辅助判断
大文件用 readAllLines() 会 OOM 吗?什么规模算“大”?
会。它把整个文件所有行一次性加载进堆内存,每行一个 String 对象,还要额外存 ArrayList 的内部数组——实际内存占用通常是文件体积的 2~5 倍。
当用户要求为 Java 代码添加注释、修改注释、审查注释、整理注释格式,或要求按照代码注释规范处理 Java 文件时,使用本技能。本技能用于统一生成和维护 Java 类注释模板、按 Git 对比 release 判断版本号、补充每行代码上方中文块注释、调整注释空行规则,并保持 Java 文件 UTF-8 无 BOM 编码。典型触发场景包括:补充类注释、更新 @version、检查 @author 来源、整理行尾注释、把注释放到代码上一行、检查注释是否符合规范、构建前检查 Java 注释风格。
经验阈值:
- ≤ 10 MB:通常安全(JVM 堆 ≥ 256 MB)
- 10–100 MB:看行数。如果单行很短(如 CSV 每行 100 字符),100 万行 ≈ 100 MB 文件,但对象数量爆炸,GC 压力大
- > 100 MB:强烈建议改用
Files.lines()流式处理,或BufferedReader手动逐行读
例如处理日志分析,别写 Files.readAllLines().stream().filter(...)——这等于先全读进内存再过滤,毫无意义。
路径不存在或没权限时,抛什么异常?怎么提前兜住?
直接抛 IOException 子类:NoSuchFileException(路径不存在)、AccessDeniedException(权限不足)、SecurityException(安全管理器拦截)。不会静默失败。
建议提前检查再读:
Path path = Paths.get("config.properties");
if (!Files.exists(path)) {
throw new IllegalArgumentException("配置文件不存在: " + path);
}
if (!Files.isReadable(path)) {
throw new IllegalArgumentException("配置文件不可读: " + path);
}
List<String> lines = Files.readAllLines(path, StandardCharsets.UTF_8);
注意:Files.exists() 和 Files.isReadable() 是轻量调用,比直接 try-catch 更早暴露问题,也方便打日志定位。
真正容易被忽略的是符号链接循环和 NFS 挂载点超时——这些可能让 exists() 卡住几秒,生产环境要加超时控制(需自行封装或换用 Files.walkFileTree() 配合 SimpleFileVisitor)。

















