Files 增强:readString / writeString#
版本信息
- 最低 JDK:11(随 JDK 11 标准库增强,无独立 JEP)
- API 文档:Java 11
java.nio.file.Files
为什么需要#
JDK 8 读一个文本文件要绕一圈:Files.readAllLines(path)(返回 List<String>,要自己拼)、或 new String(Files.readAllBytes(path), charset)(手动管字节与字符集);写文本要 Files.write(path, content.getBytes(charset))。处处要操心字符集,且很多老 API 默认用平台字符集(file.encoding),Windows 上常是 GBK,跨平台中文乱码的根源之一。JDK 11 的 Files.readString / writeString 一行读写,且默认 UTF-8——简洁又跨平台一致。
语法#
examples/files/ 里真实可运行的源码(snippets 嵌入,与示例零漂移):
package com.javamodern.files;
import java.nio.file.Files;
import java.nio.file.Path;
// JDK 11:Files.readString / writeString —— 一行读写整个文本文件,默认 UTF-8。
// 另:Path.of(JDK 11)取代 Paths.get(后者只是调 Path.of,已无需再走 Paths 工具类)。
public class FilesDemo {
/** 一行读整个文本文件(默认 UTF-8)。 */
public static String readText(Path path) throws Exception {
return Files.readString(path); // (1)
}
/** 一行写文本文件(默认 UTF-8,覆盖)。 */
public static void writeText(Path path, String content) throws Exception {
Files.writeString(path, content); // (2)
}
public static void main(String[] args) throws Exception {
Path tmp = Files.createTempFile("demo-", ".txt");
try {
writeText(tmp, "Hello, Java 11!");
System.out.println("read back = " + readText(tmp));
} finally {
Files.deleteIfExists(tmp);
}
}
}
- :material-lightbulb:
Files.readString(path)一行读全文(默认 UTF-8);Files.writeString(path, s)一行写(默认覆盖、UTF-8)。顺带,JDK 11 的Path.of("...")取代了Paths.get("...")。
运行 FilesDemo.main 的实测输出(JDK 11):
read back = Hello, Java 11!
与 JDK 8 旧写法对比#
// 读:要么拼 List,要么手动字节解码(还得记得指定字符集)
String s = new String(Files.readAllBytes(path), StandardCharsets.UTF_8);
// 写:手动转字节
Files.write(path, s.getBytes(StandardCharsets.UTF_8));
String s = Files.readString(path); // 默认 UTF-8
Files.writeString(path, s); // 默认 UTF-8、覆盖
// 需要其它字符集或追加:传第二/第三参
Files.writeString(path, s, StandardCharsets.ISO_8859_1,
StandardOpenOption.APPEND);
底层原理#
readString 是便捷封装:内部 readAllBytes 读全部字节,再用指定 Charset(缺省 UTF-8)解码为 String。writeString 则相反——用 Charset 编码为字节后写入,缺省 OpenOption 为 CREATE + WRITE + TRUNCATE_EXISTING(即覆盖)。两者都是「全量」操作(整文件入内存),适合中小文件;超大文件仍应流式读写(Files.lines / BufferedReader)。
graph LR
P["Path"] --> RS["readString:字节 + UTF-8 解码 → String"]
P --> WS["writeString:String + UTF-8 编码 → 字节(默认覆盖)"]
D["默认 UTF-8"] -.取代平台字符集.- RS
D -.取代平台字符集.- WS
style RS fill:#bbdefb
style WS fill:#bbdefb
style D fill:#c8e6c9
常见坑 / 最佳实践#
- 默认 UTF-8,不是平台字符集:与不少老 API 不同——这是好事(跨平台一致),但若代码依赖平台默认字符集的行为,迁移时要留意显式传
Charset。 - 全量读入内存:
readString把整文件读成String,别用于超大文件(GB 级);流式用Files.lines()。 - 默认是覆盖写:
writeString默认TRUNCATE_EXISTING,会清空原文件;要追加传StandardOpenOption.APPEND。 Path.of取代Paths.get:Paths.get内部只是调Path.of,新代码直接用Path.of,少一层间接。
小结#
readString/writeString 是 JDK 11 文件 API 的「减负」之作:一行读写文本、默认 UTF-8,消掉 JDK 8 的字节/字符集样板与跨平台乱码隐患——日常脚本、配置读写首选。
参考#
- Java 11
FilesJavadoc(readString、writeString、lines) - Java 11
Path.ofJavadoc