我已经用下面这个成语有一段时间了。这似乎是传播最广的,至少在我访问过的网站上。

在Java中有没有更好/不同的方法将文件读入字符串?

private String readFile(String file) throws IOException {
    BufferedReader reader = new BufferedReader(new FileReader (file));
    String         line = null;
    StringBuilder  stringBuilder = new StringBuilder();
    String         ls = System.getProperty("line.separator");

    try {
        while((line = reader.readLine()) != null) {
            stringBuilder.append(line);
            stringBuilder.append(ls);
        }

        return stringBuilder.toString();
    } finally {
        reader.close();
    }
}

当前回答

基于扫描仪的非常精简的解决方案:

Scanner scanner = new Scanner( new File("poem.txt") );
String text = scanner.useDelimiter("\\A").next();
scanner.close(); // Put this call in a finally block

或者,如果要设置字符集:

Scanner scanner = new Scanner( new File("poem.txt"), "UTF-8" );
String text = scanner.useDelimiter("\\A").next();
scanner.close(); // Put this call in a finally block

或者,使用trywithresources块,它将为您调用scanner.close():

try (Scanner scanner = new Scanner( new File("poem.txt"), "UTF-8" )) {
    String text = scanner.useDelimiter("\\A").next();
}

请记住,Scanner构造函数可以引发IOException。不要忘记导入java.io和java.util。

来源:Pat Niemeyer的博客

其他回答

读取文件中的所有文本

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的实用程序安全地简化了代码,旧的答案使用了映射字节缓冲区,在映射缓冲区被垃圾收集之前,可以防止读取的文件被删除。您可以通过此答案上的“编辑”链接查看旧版本。

该代码将规范换行符,这可能是您真正想要做的,也可能不是。

这里有一个替代方案,它没有做到这一点,而且比NIO代码更容易理解(IMO)(尽管它仍然使用java.NIO.charset.charset):

public static String readFile(String file, String csName)
            throws IOException {
    Charset cs = Charset.forName(csName);
    return readFile(file, cs);
}

public static String readFile(String file, Charset cs)
            throws IOException {
    // No real need to close the BufferedReader/InputStreamReader
    // as they're only wrapping the stream
    FileInputStream stream = new FileInputStream(file);
    try {
        Reader reader = new BufferedReader(new InputStreamReader(stream, cs));
        StringBuilder builder = new StringBuilder();
        char[] buffer = new char[8192];
        int read;
        while ((read = reader.read(buffer, 0, buffer.length)) > 0) {
            builder.append(buffer, 0, read);
        }
        return builder.toString();
    } finally {
        // Potential issue here: if this throws an IOException,
        // it will mask any others. Normally I'd use a utility
        // method which would log exceptions and swallow them
        stream.close();
    }        
}
Scanner sc = new Scanner(new File("yourFile.txt"));
sc.useDelimiter("\\Z");

String s = sc.next();

对于Java 7,这是我读取UTF-8文件的首选选项:

String content = new String(Files.readAllBytes(Paths.get(filename)), "UTF-8");

自Java7以来,JDK有了新的Java.nio.file API,它提供了许多快捷方式,因此简单的文件操作并不总是需要第三方库。


由于人们仍然对这个答案投赞成票,这里有一个在Java 11中引入的更好的解决方案:

String content = Files.readString(path);

如果您正在寻找不涉及第三方库(例如Commons I/O)的替代方案,可以使用Scanner类:

private String readFile(String pathname) throws IOException {

    File file = new File(pathname);
    StringBuilder fileContents = new StringBuilder((int)file.length());        

    try (Scanner scanner = new Scanner(file)) {
        while(scanner.hasNextLine()) {
            fileContents.append(scanner.nextLine() + System.lineSeparator());
        }
        return fileContents.toString();
    }
}