将文件读入字符串的最简单方法是什么?

286

我想把一个简单的文本文件读入一个字符串。当然,通常的方法是获取输入流并使用readLine()迭代,并将内容读入字符串中。

在过去的许多次中我已经这样做了,但我想知道如何用最少的代码量做到这点?Java 中没有像 String fileContents = XXX.readFile(myFile/*File*/) 这样简单的东西吗?

我知道有像 Apache Commons IO 这样提供简化的库,或者我可以编写一个简单的 Util 类来做到这一点。但我想知道的是,既然这是如此频繁的操作,每个人都需要,那为什么 Java 不提供这样简单的函数呢?难道真的没有一个方法可以读取文件并将其以默认或指定的编码方式转换成字符串吗?


Java 11的Files.readString(path)可以用来将文件读取为字符串,更简洁地实现。https://howtodoinjava.com/java/io/java-read-file-to-string-examples/#1-using-files-readstring-java-11 - undefined
9个回答

374

是的,你可以用一行代码实现这个功能(尽管为了健壮的IOException处理,你不想这么做)。

String content = new Scanner(new File("filename")).useDelimiter("\\Z").next();
System.out.println(content);

这里使用了一个java.util.Scanner,告诉它用\Z来分隔输入,这是字符串结尾的锚点。这最终使输入只有一个实际标记,即整个文件,因此可以通过一次调用next()来读取。

有一个构造函数,它接受一个File和一个String charSetName(还有许多其他重载)。这两个构造函数可能会抛出FileNotFoundException,但像所有Scanner方法一样,除了这些构造函数,不会抛出IOException

如果发生了IOException,您可以通过ioException()方法查询Scanner本身是否发生了异常。在读取内容后,您可能还想显式 close() Scanner,因此最好将Scanner引用存储在一个局部变量中。

另请参阅

相关问题


第三方库选项

为了完整起见,以下是一些非常有声誉和高度实用的第三方库选项:

Guava

com.google.common.io.Files 包含许多有用的方法。这里重要的是:

Apache Commons/IO

org.apache.commons.io.IOUtils也提供了类似的功能:

  • String toString(InputStream, String encoding)
    • 使用指定的字符编码,将InputStream的内容作为String获取
  • List readLines(InputStream, String encoding)
    • ...作为(原始)ListString,每行一个条目

相关问题


2
请参见下面的解决方案,其中Java 7机制基本上只需一行代码即可使用默认API。与许多其他事情一样,Java已经稍微前进了一步。 - Jim
7
很遗憾,扫描器解决方案在空文件情况下失败(抛出NoSuchElementException异常)。 - Daniel Alder
2
我已经使用了一段时间,但事实证明它并不总是有效!有时候\\Z会出现在文件中,导致操作失败。 - wvdz
8
return new Scanner(new URL(url).openStream(), "UTF-8").useDelimiter("\A").next(); 更好,因为它不会在空文件上失败。 - Guy
2
如果您使用的文本文件大于1024字节,请避免这种情况。扫描器(至少在Android上)会将结果字符串截断为1024字节。 - Udo Klimaschewski
显示剩余5条评论

224
从Java 7 (API说明) 开始,您可以执行以下操作:

new String(Files.readAllBytes(Paths.get(filePath)), StandardCharsets.UTF_8);

其中filePath是代表要加载的文件的字符串。

2
我相信只有当文件在平台的默认字符集中时,这才能正常工作。 - Paul
7
@Paul,我认为这作为默认值是可以的。在构建新字符串时,您可以始终指定字符集。 - Mike Braun
2
这种解决方案的缺点是无法处理类路径资源(通过Class.getResource()或类似方法获得),而Scanner解决方案在这种情况下可以工作。 - LordOfThePigs
2
我上一条评论的纯Java版本: String iAmAString = new String(Files.readAllBytes(new File(Thread.currentThread().getContextClassLoader().getResource("iAmAFile").toURI()).toPath())); - Rondo
2
@Rondo 并非所有classpath资源都对应于“File”(例如,在jar内部的资源),因此通常情况下不能用于此。 - ddekany
显示剩余6条评论

48

你可以使用 Apache Commons IO 库。

FileInputStream fisTargetFile = new FileInputStream(new File("test.txt"));

String targetFileStr = IOUtils.toString(fisTargetFile, "UTF-8");

19
为什么Java程序员总是试图使用第三方库,而Java本身已经有完全能够胜任的内置工具呢? - Jay
5
当然,这些设施“完全正常”,只是其中一些过于复杂了。不过,我同意仅为此目的使用另一个库有点过度杀伐。 - Andrea Lazzarotto
4
这并不是过度的行为,而是一个机会。这个机会可以开始使用Apache Commons库并提高工作效率,或者您也可以选择Guava。 - Florian F
1
这只是三行代码 - 你需要关闭流。 - Pavel Vlasov

39

这个方法应该适合你:

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;

public static void main(String[] args) throws IOException {
    String content = new String(Files.readAllBytes(Paths.get("abc.java")));
}

谢谢!与大多数解决方案相比,这个解决方案不会删除尾随的换行符。一个改进:new String(…, StandardCharsets.UTF_8) - mirabilos

27

使用 Apache Commons IO 库。

import org.apache.commons.io.FileUtils;

//...

String contents = FileUtils.readFileToString(new File("/path/to/the/file"), "UTF-8")
你可以查看方法的 javadoc 获取细节。

11
不要自己编写工具类来完成此操作 - 我建议使用Guava,它充满了各种好处。在这种情况下,如果您只是读取文件,则需要Files类,如果需要更通用的读取,则需要CharStreams。它有将数据读入字符串列表(readLines)或完全读取的方法(toString)。
它也有类似的有用方法用于二进制数据。然后还有库的其余部分...
我同意没有类似标准库中的东西很烦人。仅仅能够向FileReader提供CharSet就可以让生活变得稍微简单一点...

1
在Java 7上,您会推荐使用Guava还是new String(Files.readAllBytes(Paths.get(filePath))) - Manu Manjunath
2
@Manu:我绝对不会使用那个 - 我至少会指定一个字符编码。但是由于Guava通常是有用的,无论使用Java 8或者其他,你也可能想使用Files.toString,因为它非常容易。 - Jon Skeet

8

7

很遗憾,不行。

我同意这样频繁的操作应该有比逐行复制输入更简单的实现方式,但你需要编写辅助方法或使用外部库。


2
我发现被接受的答案并不总是有效,因为\\Z可能出现在文件中。另一个问题是,如果您没有正确的字符集,可能会发生许多意外情况,这可能会导致扫描器仅读取文件的一部分。
解决方案是使用您确定永远不会出现在文件中的定界符。然而,理论上这是不可能的。我们可以做的是使用一个具有极小概率出现在文件中的定界符,这个定界符是Java本地支持的UUID
String content = new Scanner(file, "UTF-8")
    .useDelimiter(UUID.randomUUID().toString()).next();

“\Z 可能出现在文件中”是什么意思?\Z(解码后)是java.util.regex.Pattern的模式之一,而不是字面字符序列。文件中的字面字符序列“\Z”将无法与模式\Z匹配。 - Kuro
@KuroKurosaka 我不是指字面上的序列\Z,我是指文件中可能实际上在文件中间包含了'字符串结束'字符。这种情况曾经发生在我身上,也是为什么被接受的答案对我无效的原因。 - wvdz
我明白了。您在考虑一种情况,即某个软件或操作系统决定使用除CR或LF(或在Microsoft的情况下两者都使用)以外的控制字符作为EOL序列。我会这样写:例如,如果使用Control-Z作为EOF字符,则会写成“'\u001A'”。 - Kuro

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接