1675

一段时间以来,我一直在使用下面的成语。它似乎是最广泛的,至少在我访问过的网站上。

有没有更好/不同的方法将文件读入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();
    }
}
4

33 回答 33

1742

从文件中读取所有文本

Java 11 添加了readString()方法来读取小文件String,保留行终止符:

String content = Files.readString(path, StandardCharsets.US_ASCII);

对于 Java 7 和 11 之间的版本,这是一个紧凑、健壮的习惯用法,包含在一个实用方法中:

static String readFile(String path, Charset encoding)
  throws IOException
{
  byte[] encoded = Files.readAllBytes(Paths.get(path));
  return new String(encoded, encoding);
}

从文件中读取文本行

Java 7 添加了一种方便的方法,可以将文件读取为文本行,表示为List<String>. 这种方法是“有损的”,因为行分隔符从每行的末尾被剥离。

List<String> lines = Files.readAllLines(Paths.get(path), encoding);

Java 8 添加了Files.lines()生成Stream<String>. 同样,这种方法是有损的,因为行分隔符被剥离。如果IOException在读取文件时遇到 an ,则将其包装在 中UncheckedIOException,因为Stream不接受引发检查异常的 lambda。

try (Stream<String> lines = Files.lines(path, encoding)) {
  lines.forEach(System.out::println);
}

Stream确实需要一个close()电话;这在 API 上的记录很差,我怀疑很多人甚至没有注意到Stream有一个close()方法。一定要使用如图所示的 ARM 块。

如果您正在使用文件以外的源,则可以改用该lines()方法BufferedReader

内存利用率

第一种保留换行符的方法可能会暂时需要几倍于文件大小的内存,因为在短时间内原始文件内容(字节数组)和解码的字符(每个字符都是 16 位,即使已编码)作为文件中的 8 位)一次驻留在内存中。应用到您知道相对于可用内存较小的文件是最安全的。

第二种方法,读取行,通常更节省内存,因为用于解码的输入字节缓冲区不需要包含整个文件。但是,它仍然不适合相对于可用内存非常大的文件。

为了读取大文件,您需要对程序进行不同的设计,即从流中读取一大块文本,对其进行处理,然后继续下一个,重用相同的固定大小的内存块。在这里,“大”取决于计算机规格。如今,这个阈值可能是数 GB 的 RAM。Stream<String>如果您输入的“记录”恰好是单独的行,则使用第三种方法是一种方法。(使用 的readLine()方法BufferedReader是这种方法的程序等价物。)

字符编码

原始帖子中的示例中缺少的一件事是字符编码。在某些特殊情况下,平台默认值是您想要的,但它们很少见,您应该能够证明您的选择是合理的。

该类StandardCharsets为所有 Java 运行时所需的编码定义了一些常量:

String content = readFile("test.txt", StandardCharsets.UTF_8);

平台默认值可从Charset本身获得:

String content = readFile("test.txt", Charset.defaultCharset());

注意:这个答案在很大程度上取代了我的 Java 6 版本。Java 7 的实用程序安全地简化了代码,并且使用映射字节缓冲区的旧答案阻止了读取的文件被删除,直到映射缓冲区被垃圾收集。您可以通过此答案的“已编辑”链接查看旧版本。

于 2008-11-28T18:56:13.693 回答
389

如果您愿意使用外部库,请查看Apache Commons IO (200KB JAR)。它包含一个方法,允许您使用一行代码org.apache.commons.io.FileUtils.readFileToString()将整个内容读File入 a中。String

例子:

import java.io.*;
import java.nio.charset.*;
import org.apache.commons.io.*;

public String readFile() throws IOException {
    File file = new File("data.txt");
    return FileUtils.readFileToString(file, StandardCharsets.UTF_8);
}
于 2008-11-28T18:44:36.697 回答
190

一个非常精益的解决方案,基于Scanner

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

或者,使用try-with-resources块,它会调用scanner.close()你:

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

请记住,Scanner构造函数可以抛出一个IOException. 并且不要忘记导入java.iojava.util.

资料来源:Pat Niemeyer 的博客

于 2011-09-16T20:02:17.840 回答
148
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;

爪哇 7

String content = new String(Files.readAllBytes(Paths.get("readMe.txt")), StandardCharsets.UTF_8);

爪哇 11

String content = Files.readString(Paths.get("readMe.txt"));
于 2016-10-28T07:04:17.057 回答
81

如果您正在寻找不涉及第三方库(例如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();
    }
}
于 2008-11-28T19:00:35.183 回答
72

Guava的方法类似于 Willi aus Rohr 提到的 Commons IOUtils 中的方法:

import com.google.common.base.Charsets;
import com.google.common.io.Files;

// ...

String text = Files.toString(new File(path), Charsets.UTF_8);

PiggyPiglet 的 EDIT
Files#toString已弃用,将于 2019 年 10 月移除。改为使用 Files.asCharSource(new File(path), StandardCharsets.UTF_8).read();

奥斯卡·雷耶斯编辑

这是引用库上的(简化的)底层代码:

InputStream in = new FileInputStream(file);
byte[] b  = new byte[file.length()];
int len = b.length;
int total = 0;

while (total < len) {
  int result = in.read(b, total, len - total);
  if (result == -1) {
    break;
  }
  total += result;
}

return new String( b , Charsets.UTF_8 );

编辑(由 Jonik 提供):以上内容与最近 Guava 版本的源代码不匹配。对于当前源,请参阅com.google.common.io包中的FilesCharStreamsByteSourceCharSource类。

于 2010-02-08T20:08:37.603 回答
59
import java.nio.file.Files;

…………

 String readFile(String filename) {
            File f = new File(filename);
            try {
                byte[] bytes = Files.readAllBytes(f.toPath());
                return new String(bytes,"UTF-8");
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return "";
    }
于 2012-04-16T14:33:59.960 回答
52

如果你需要一个字符串处理(并行处理),Java 8 有很棒的 Stream API。

String result = Files.lines(Paths.get("file.txt"))
                    .parallel() // for parallel processing 
                    .map(String::trim) // to change line   
                    .filter(line -> line.length() > 2) // to filter some lines by a predicate                        
                    .collect(Collectors.joining()); // to join lines

JDK 示例中提供了更多示例sample/lambda/BulkDataOperations,可从Oracle Java SE 8 下载页面下载

另一个班轮示例

String out = String.join("\n", Files.readAllLines(Paths.get("file.txt")));
于 2014-10-29T08:51:58.050 回答
51

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

这是一个不这样做的替代方案,并且(IMO)比 NIO 代码更易于理解(尽管它仍然使用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();
    }        
}
于 2008-11-28T19:56:35.287 回答
31

收集了从磁盘或网络读取文件作为字符串的所有可能方法。

  • 番石榴:谷歌使用类ResourcesFiles

    static Charset charset = com.google.common.base.Charsets.UTF_8;
    public static String guava_ServerFile( URL url ) throws IOException {
        return Resources.toString( url, charset );
    }
    public static String guava_DiskFile( File file ) throws IOException {
        return Files.toString( file, charset );
    }
    

  • APACHE -使用 IOUtils、FileUtils 类的COMMONS IO

    static Charset encoding = org.apache.commons.io.Charsets.UTF_8;
    public static String commons_IOUtils( URL url ) throws IOException {
        java.io.InputStream in = url.openStream();
        try {
            return IOUtils.toString( in, encoding );
        } finally {
            IOUtils.closeQuietly(in);
        }
    }
    public static String commons_FileUtils( File file ) throws IOException {
        return FileUtils.readFileToString( file, encoding );
        /*List<String> lines = FileUtils.readLines( fileName, encoding );
        return lines.stream().collect( Collectors.joining("\n") );*/
    }
    

  • 使用Stream API的Java 8 BufferReader

    public static String streamURL_Buffer( URL url ) throws IOException {
        java.io.InputStream source = url.openStream();
        BufferedReader reader = new BufferedReader( new InputStreamReader( source ) );
        //List<String> lines = reader.lines().collect( Collectors.toList() );
        return reader.lines().collect( Collectors.joining( System.lineSeparator() ) );
    }
    public static String streamFile_Buffer( File file ) throws IOException {
        BufferedReader reader = new BufferedReader( new FileReader( file ) );
        return reader.lines().collect(Collectors.joining(System.lineSeparator()));
    }
    

  • 带有正则表达式的扫描仪类\A。与输入的开头匹配。

    static String charsetName = java.nio.charset.StandardCharsets.UTF_8.toString();
    public static String streamURL_Scanner( URL url ) throws IOException {
        java.io.InputStream source = url.openStream();
        Scanner scanner = new Scanner(source, charsetName).useDelimiter("\\A");
        return scanner.hasNext() ? scanner.next() : "";
    }
    public static String streamFile_Scanner( File file ) throws IOException {
        Scanner scanner = new Scanner(file, charsetName).useDelimiter("\\A");
        return scanner.hasNext() ? scanner.next() : "";
    }
    

  • Java 7 ( java.nio.file.Files.readAllBytes)

    public static String getDiskFile_Java7( File file ) throws IOException {
        byte[] readAllBytes = java.nio.file.Files.readAllBytes(Paths.get( file.getAbsolutePath() ));
        return new String( readAllBytes );
    }
    

  • BufferedReader使用InputStreamReader.

    public static String getDiskFile_Lines( File file ) throws IOException {
        StringBuffer text = new StringBuffer();
        FileInputStream fileStream = new FileInputStream( file );
        BufferedReader br = new BufferedReader( new InputStreamReader( fileStream ) );
        for ( String line; (line = br.readLine()) != null; )
            text.append( line + System.lineSeparator() );
        return text.toString();
    }
    

使用 main 方法访问上述方法的示例。

public static void main(String[] args) throws IOException {
    String fileName = "E:/parametarisation.csv";
    File file = new File( fileName );

    String fileStream = commons_FileUtils( file );
            // guava_DiskFile( file );
            // streamFile_Buffer( file );
            // getDiskFile_Java7( file );
            // getDiskFile_Lines( file );
    System.out.println( " File Over Disk : \n"+ fileStream );


    try {
        String src = "https://code.jquery.com/jquery-3.2.1.js";
        URL url = new URL( src );

        String urlStream = commons_IOUtils( url );
                // guava_ServerFile( url );
                // streamURL_Scanner( url );
                // streamURL_Buffer( url );
        System.out.println( " File Over Network : \n"+ urlStream );
    } catch (MalformedURLException e) {
        e.printStackTrace();
    }
}

@看

于 2018-05-29T10:09:02.563 回答
26

如果它是一个文本文件,为什么不使用apache commons-io

它有以下方法

public static String readFileToString(File file) throws IOException

如果您希望将这些行作为列表使用

public static List<String> readLines(File file) throws IOException
于 2011-10-17T15:34:03.290 回答
25

从 JDK 11 开始:

String file = ...
Path path = Paths.get(file);
String content = Files.readString(path);
// Or readString(path, someCharset), if you need a Charset different from UTF-8
于 2018-06-26T14:26:44.880 回答
17

将文件读取为二进制文件并在最后进行转换

public static String readFileAsString(String filePath) throws IOException {
    DataInputStream dis = new DataInputStream(new FileInputStream(filePath));
    try {
        long len = new File(filePath).length();
        if (len > Integer.MAX_VALUE) throw new IOException("File "+filePath+" too large, was "+len+" bytes.");
        byte[] bytes = new byte[(int) len];
        dis.readFully(bytes);
        return new String(bytes, "UTF-8");
    } finally {
        dis.close();
    }
}
于 2010-04-18T07:34:29.137 回答
16

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

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

从 Java 7 开始,JDK 有了新的java.nio.fileAPI,它提供了许多快捷方式,因此简单的文件操作并不总是需要 3rd 方库。

于 2016-04-19T16:39:06.130 回答
15

Java 试图在它所做的所有事情上都非常通用和灵活。结果,在脚本语言中相对简单的东西(您的代码将open(file).read()在 python 中替换为“”)要复杂得多。除了使用外部库(如Willi aus Rohr提到的)外,似乎没有更短的方法可以做到这一点。您的选择:

  • 使用外部库。
  • 将此代码复制到您的所有项目中。
  • 创建您自己的迷你库,其中包含您经常使用的功能。

您最好的选择可能是第二个,因为它具有最少的依赖性。

于 2008-11-28T18:52:37.833 回答
11

使用 JDK 8 或更高版本:

没有使用外部库

您可以从文件内容创建一个新的 String 对象(使用java.nio.file包中的类):

public String readStringFromFile(String filePath) throws IOException {
    String fileContent = new String(Files.readAllBytes(Paths.get(filePath)));
    return fileContent;
}
于 2018-06-21T05:46:40.693 回答
7

同一主题有一个变体,它使用 for 循环而不是 while 循环来限制 line 变量的范围。是否“更好”是个人品味的问题。

for(String line = reader.readLine(); line != null; line = reader.readLine()) {
    stringBuilder.append(line);
    stringBuilder.append(ls);
}
于 2008-11-28T20:33:13.497 回答
7

如果您无权访问Files该类,则可以使用本机解决方案。

static String readFile(File file, String charset)
        throws IOException
{
    FileInputStream fileInputStream = new FileInputStream(file);
    byte[] buffer = new byte[fileInputStream.available()];
    int length = fileInputStream.read(buffer);
    fileInputStream.close();
    return new String(buffer, 0, length, charset);
}
于 2015-01-06T18:52:59.440 回答
4

使用来自 Apache commons-io的IOUtilsStringWriter的灵活解决方案:

Reader input = new FileReader();
StringWriter output = new StringWriter();
try {
  IOUtils.copy(input, output);
} finally {
  input.close();
}
String fileContents = output.toString();

它适用于任何阅读器或输入流(不仅仅是文件),例如从 URL 读取时。

于 2012-02-15T10:47:35.240 回答
3
public static String slurp (final File file)
throws IOException {
    StringBuilder result = new StringBuilder();

    BufferedReader reader = new BufferedReader(new FileReader(file));

    try {
        char[] buf = new char[1024];

        int r = 0;

        while ((r = reader.read(buf)) != -1) {
            result.append(buf, 0, r);
        }
    }
    finally {
        reader.close();
    }

    return result.toString();
}
于 2010-02-08T19:51:12.280 回答
3

这个用的方法RandomAccessFile.readFully,好像从JDK 1.0就可以了!

public static String readFileContent(String filename, Charset charset) throws IOException {
    RandomAccessFile raf = null;
    try {
        raf = new RandomAccessFile(filename, "r");
        byte[] buffer = new byte[(int)raf.length()];
        raf.readFully(buffer);
        return new String(buffer, charset);
    } finally {
        closeStream(raf);
    }
} 


private static void closeStream(Closeable c) {
    if (c != null) {
        try {
            c.close();
        } catch (IOException ex) {
            // do nothing
        }
    }
}
于 2011-10-23T07:43:29.137 回答
3

请注意,使用fileInputStream.available()返回的整数时不必表示实际文件大小,而是系统应该能够在不阻塞 IO 的情况下从流中读取的猜测字节数。一种安全简单的方法可能如下所示

public String readStringFromInputStream(FileInputStream fileInputStream) {
    StringBuffer stringBuffer = new StringBuffer();
    try {
        byte[] buffer;
        while (fileInputStream.available() > 0) {
            buffer = new byte[fileInputStream.available()];
            fileInputStream.read(buffer);
            stringBuffer.append(new String(buffer, "ISO-8859-1"));
        }
    } catch (FileNotFoundException e) {
    } catch (IOException e) { }
    return stringBuffer.toString();
}

需要考虑的是,这种方式不适用于 UTF-8 这样的多字节字符编码。

于 2013-03-15T09:09:56.443 回答
3

可以试试 Scanner 和 File 类,几行解决

 try
{
  String content = new Scanner(new File("file.txt")).useDelimiter("\\Z").next();
  System.out.println(content);
}
catch(FileNotFoundException e)
{
  System.out.println("not found!");
}
于 2017-02-07T06:10:25.647 回答
3

根据@erickson 的回答,您可以使用:

public String readAll(String fileName) throws IOException {
    List<String> lines = Files.readAllLines(new File(fileName).toPath());
    return String.join("\n", lines.toArray(new String[lines.size()]));
}
于 2018-04-01T13:34:54.697 回答
3

用户java.nio.Files读取文件的所有行。

public String readFile() throws IOException {
        File fileToRead = new File("file path");
        List<String> fileLines = Files.readAllLines(fileToRead.toPath());
        return StringUtils.join(fileLines, StringUtils.EMPTY);
}
于 2018-10-26T06:38:33.117 回答
2

我还不能评论其他条目,所以我就把它留在这里。

这里的最佳答案之一(https://stackoverflow.com/a/326448/1521167):

private String readFile(String pathname) throws IOException {

File file = new File(pathname);
StringBuilder fileContents = new StringBuilder((int)file.length());
Scanner scanner = new Scanner(file);
String lineSeparator = System.getProperty("line.separator");

try {
    while(scanner.hasNextLine()) {        
        fileContents.append(scanner.nextLine() + lineSeparator);
    }
    return fileContents.toString();
} finally {
    scanner.close();
}
}

仍然有一个缺陷。它总是将换行符放在字符串的末尾,这可能会导致一些奇怪的错误。我的建议是将其更改为:

    private String readFile(String pathname) throws IOException {
    File file = new File(pathname);
    StringBuilder fileContents = new StringBuilder((int) file.length());
    Scanner scanner = new Scanner(new BufferedReader(new FileReader(file)));
    String lineSeparator = System.getProperty("line.separator");

    try {
        if (scanner.hasNextLine()) {
            fileContents.append(scanner.nextLine());
        }
        while (scanner.hasNextLine()) {
            fileContents.append(lineSeparator + scanner.nextLine());
        }
        return fileContents.toString();
    } finally {
        scanner.close();
    }
}
于 2013-12-13T09:33:32.890 回答
2

在 Scanner 之后 Ctrl+F'ing 后,我认为 Scanner 解决方案也应该列出。在最容易阅读的时尚中,它是这样的:

public String fileToString(File file, Charset charset) {
  Scanner fileReader = new Scanner(file, charset);
  fileReader.useDelimiter("\\Z"); // \Z means EOF.
  String out = fileReader.next();
  fileReader.close();
  return out;
}

如果您使用 Java 7 或更新版本(并且您确实应该)考虑使用 try-with-resources 以使代码更易于阅读。没有更多的点关闭的东西乱扔所有东西。但这主要是我认为的风格选择。

我发布这个主要是为了完成主义,因为如果你需要做很多事情,java.nio.file.Files中应该有一些东西应该可以更好地完成这项工作。

我的建议是使用Files#readAllBytes(Path)来获取所有字节,并将其提供给 new String(byte[] Charset)以从中获取您可以信任的字符串。字符集在你的一生中对你来说很重要,所以现在要小心这些东西。

其他人提供了代码和东西,我不想窃取他们的荣耀。;)

于 2015-11-29T14:09:52.750 回答
2

使用这个库,它是一行:

String data = IO.from(new File("data.txt")).toString();
于 2016-12-10T15:55:40.430 回答
2

此外,如果您的文件恰好在 jar 中,您也可以使用以下命令:

public String fromFileInJar(String path) {
    try ( Scanner scanner 
            = new Scanner(getClass().getResourceAsStream(path))) {
        return scanner.useDelimiter("\\A").next();
    }
}

/ 例如,如果您的 jar是

my.jar/com/some/thing/a.txt

然后你想像这样调用它:

String myTxt = fromFileInJar("/com/com/thing/a.txt");
于 2017-02-15T21:15:44.533 回答
2

在一行(Java 8)中,假设您有一个阅读器:

String sMessage = String.join("\n", reader.lines().collect(Collectors.toList()));
于 2017-03-15T02:39:05.237 回答
0

使用代码:

File file = new File("input.txt");
BufferedInputStream bin = new BufferedInputStream(new FileInputStream(
                file));
byte[] buffer = new byte[(int) file.length()];
bin.read(buffer);
String fileStr = new String(buffer);

fileStr 包含字符串中的输出。

于 2017-01-16T06:53:39.120 回答
0
Scanner sc = new Scanner(new File("yourFile.txt"));
sc.useDelimiter("\\Z");

String s = sc.next();
于 2022-02-04T18:39:10.757 回答
-2

在 java 8 中,有一个新的类

java.util.stream.Stream

流表示一系列元素并支持不同类型的操作以对这些元素执行计算

阅读更多相关信息:

甲骨文文档

这里有一个例子:

import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.stream.Stream;

public Class ReadFile{
  public  static String readFile(String filePath) {
 StringBuilder  stringBuilder = new StringBuilder();
    String ls = System.getProperty("line.separator");
        try {

            try (Stream<String> lines = Files.lines(Paths.get(filePath), StandardCharsets.UTF_8)) {
                for (String line : (Iterable<String>) lines::iterator) {


                      stringBuilder.append(line);
                      stringBuilder.append(ls);


                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

      return stringBuilder.toString(); 


}

}
于 2016-12-06T12:00:40.777 回答