我需要使用Java逐行读取大约5-6 GB的大型文本文件。

我怎样才能快速做到呢?


当前回答

在Java 8中,除了使用Files.lines(),还有另一种方法。如果您的输入源不是文件,而是更抽象的东西,如Reader或InputStream,则可以通过BufferedReaders lines()方法对行进行流处理。

例如:

try (BufferedReader reader = new BufferedReader(...)) {
  reader.lines().forEach(line -> processLine(line));
}

BufferedReader读取的每个输入行都会调用processLine()。

其他回答

你也可以使用Apache Commons IO:

File file = new File("/home/user/file.txt");
try {
    List<String> lines = FileUtils.readLines(file);
} catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

在Java 8中,你可以这样做:

try (Stream<String> lines = Files.lines (file, StandardCharsets.UTF_8))
{
    for (String line : (Iterable<String>) lines::iterator)
    {
        ;
    }
}

一些注释:由Files返回的流。行(不像大多数流)需要关闭。由于这里提到的原因,我避免使用forEach()。奇怪的代码(Iterable<String>) lines::iterator将一个Stream转换为一个Iterable。

一种常见的模式是使用

try (BufferedReader br = new BufferedReader(new FileReader(file))) {
    String line;
    while ((line = br.readLine()) != null) {
       // process the line.
    }
}

如果假设没有字符编码,则可以更快地读取数据。例如,ASCII-7,但它不会有太大的区别。很有可能您对数据的处理将花费更长的时间。

EDIT:一种不太常用的模式,可以避免行泄漏的范围。

try(BufferedReader br = new BufferedReader(new FileReader(file))) {
    for(String line; (line = br.readLine()) != null; ) {
        // process the line.
    }
    // line is not visible here.
}

更新:在Java 8中你可以这样做

try (Stream<String> stream = Files.lines(Paths.get(fileName))) {
        stream.forEach(System.out::println);
}

注意:你必须将Stream放在try-with-resource块中,以确保对其调用#close方法,否则底层文件句柄永远不会关闭,直到GC在很久之后才关闭。

对于使用Kotlin的Android开发者来说:

val myFileUrl = object{}.javaClass.getResource("/vegetables.txt")
val file = File(myFileUrl.toURI())
file
    .bufferedReader()
    .lineSequence()
    .forEach(::println)

Or:

val myFileUrl = object{}.javaClass.getResource("/vegetables.txt")
val file = File(myFileUrl.toURI())
file.useLines { lines ->
    lines.forEach(::println)
}

注:

txt文件应该在您的类路径中(例如,在src/main/resources目录中) 上述解决方案都默认将文件编码处理为UTF-8。您可以指定所需的编码作为函数的参数。 上述解决方案不需要任何进一步的操作,如关闭文件或读取器。它们由Kotlin标准库自动处理。

下面是一个完整的错误处理示例,并支持java 7之前的字符集规范。在Java 7中,您可以使用try-with-resources语法,这使得代码更简洁。

如果你只想要默认字符集,你可以跳过InputStream,使用FileReader。

InputStream ins = null; // raw byte-stream
Reader r = null; // cooked reader
BufferedReader br = null; // buffered for readLine()
try {
    String s;
    if (true) {
        String data = "#foobar\t1234\n#xyz\t5678\none\ttwo\n";
        ins = new ByteArrayInputStream(data.getBytes());
    } else {
        ins = new FileInputStream("textfile.txt");
    }
    r = new InputStreamReader(ins, "UTF-8"); // leave charset out for default
    br = new BufferedReader(r);
    while ((s = br.readLine()) != null) {
        System.out.println(s);
    }
}
catch (Exception e)
{
    System.err.println(e.getMessage()); // handle exception
}
finally {
    if (br != null) { try { br.close(); } catch(Throwable t) { /* ensure close happens */ } }
    if (r != null) { try { r.close(); } catch(Throwable t) { /* ensure close happens */ } }
    if (ins != null) { try { ins.close(); } catch(Throwable t) { /* ensure close happens */ } }
}

下面是Groovy版本,有完整的错误处理:

File f = new File("textfile.txt");
f.withReader("UTF-8") { br ->
    br.eachLine { line ->
        println line;
    }
}