读取文件中的所有文本
Java 11添加了readString()方法,将小文件作为字符串读取,保留了行终止符:
String content = Files.readString(path, encoding);
对于Java 7和11之间的版本,这里有一个紧凑、健壮的习惯用法,用实用方法概括:
static String readFile(String path, Charset encoding)
throws IOException
{
byte[] encoded = Files.readAllBytes(Paths.get(path));
return new String(encoded, encoding);
}
从文件中读取文本行
Java7添加了一种方便的方法,以文本行形式读取文件,表示为List<String>。这种方法是“有损的”,因为行分隔符是从每行的末尾剥离的。
List<String> lines = Files.readAllLines(Paths.get(path), encoding);
Java8添加了Files.line()方法来生成Stream<String>。同样,这种方法是有损耗的,因为行分隔符被剥离了。如果在读取文件时遇到IOException,它将被包装在UncheckedIOException中,因为Stream不接受引发选中异常的lambda。
try (Stream<String> lines = Files.lines(path, encoding)) {
lines.forEach(System.out::println);
}
此流确实需要close()调用;这在API中记录得很差,我怀疑很多人甚至没有注意到Stream有一个close()方法。确保使用如图所示的ARM块。
如果使用的是文件以外的源,则可以改用BufferedReader中的lines()方法。
内存利用率
如果文件相对于可用内存足够小,那么一次读取整个文件可能会很好。但是,如果文件太大,一次读取一行,处理它,然后在继续下一行之前丢弃它可能是更好的方法。以这种方式进行流处理可以消除作为内存需求因素的总文件大小。
字符编码
原始文章中的示例缺少的一点是字符编码。这种编码通常无法从文件本身确定,并且需要元数据(如HTTP头)来传递这一重要信息。
StandardCharsets类为所有Java运行时所需的编码定义了一些常量:
String content = readFile("test.txt", StandardCharsets.UTF_8);
平台默认值可从Charset类本身获得:
String content = readFile("test.txt", Charset.defaultCharset());
在某些特殊情况下,平台默认值是您想要的,但这种情况很少见。您应该能够证明您的选择是合理的,因为平台默认值是不可移植的。一个可能正确的例子是读取标准输入或写入标准输出时。
注意:这个答案很大程度上取代了我的Java6版本。Java7的实用程序安全地简化了代码,旧的答案使用了映射字节缓冲区,在映射缓冲区被垃圾收集之前,可以防止读取的文件被删除。您可以通过此答案上的“编辑”链接查看旧版本。