如何使用 Files.lines(...).forEach(...) 读取文件?

Posted

技术标签:

【中文标题】如何使用 Files.lines(...).forEach(...) 读取文件?【英文标题】:How to read from files with Files.lines(...).forEach(...)? 【发布时间】:2014-06-10 04:21:24 【问题描述】:

我目前正在尝试从我拥有的纯文本文件中读取行。我在另一个 ***(Reading a plain text file in Java) 上发现你可以使用 Files.lines(..).forEach(..) 但是我实际上无法弄清楚如何使用 for each 函数来逐行读取文本,有人知道在哪里查找或如何查找吗?

【问题讨论】:

该方法已经在读取文件的每一行,您可以将该行存储在 String 变量中并用它做其他事情... 嗯,您应该阅读有关 Java 8 和 lambdas 的信息;特别是这里,关于Consumer 和单一抽象方法的概念 【参考方案1】:

test.txt 的示例内容

Hello
Stack
Over
Flow
com

使用lines()forEach() 方法从该文本文件中读取的代码。

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.Stream;

public class FileLambda 

    public static void main(String args[]) 
        Path path = Paths.of("/root/test.txt");
        try (Stream<String> lines = Files.lines(path)) 
            lines.forEach(s -> System.out.println(s));
         catch (IOException ex) 
          // do something or re-throw...
        
    
    

【讨论】:

您可以使用方法参考:System.out::println,仍然会被翻译成相同的字节码。 还有一点:你不应该将Stream 存储为变量,因为它可能会混淆一些读者使用它两次或更多次,这是被禁止的。相反,您可以使用readAllLines 将其保存到List,然后使用此列表中的stream() 方法。 对流使用 try-with-resources 以确保它自动关闭:try (Stream&lt;String&gt; lines = Files.lines(path)) @DmitryGinzburg 您是否会将Stream 存储为一个变量,以用于对于readAllLines 来说太大的文件? 请不要在生产代码中写这样的空catch块。【参考方案2】:

避免返回一个列表:

List<String> lines = Files.readAllLines(path); //WARN

请注意,调用Files::readAllLines 时会读取整个文件,生成的字符串数组会立即将文件的所有内容存储在内存中。 因此,如果文件非常大,您可能会遇到OutOfMemoryError 试图将其全部加载到内存中。

改用流:使用返回Stream&lt;String&gt; 对象的Files.lines(Path) 方法,不会遇到同样的问题。 文件的内容是惰性读取和处理的,这意味着在任何给定时间,只有一小部分文件存储在内存中。

Files.lines(path).forEach(System.out::println);

【讨论】:

我有一个疑问。 Files.lines() 会返回每一行的流还是会从整个文件中返回一个流?请澄清。 "将文件中的所有行作为流读取。" docs.oracle.com/javase/8/docs/api/java/nio/file/…【参考方案3】:

使用 Java 8,如果文件存在于 classpath

Files.lines(Paths.get(ClassLoader.getSystemResource("input.txt")
                    .toURI())).forEach(System.out::println);

【讨论】:

【参考方案4】:

Files.lines(Path) 需要 Path 参数并返回 Stream&lt;String&gt;Stream#forEach(Consumer) 需要 Consumer 参数。所以调用该方法,传递给它一个Consumer。必须实现该对象才能为每一行执行您想要的操作。

这是 Java 8,因此您可以使用 lambda 表达式或方法引用来提供 Consumer 参数。

【讨论】:

【参考方案5】:

我已经创建了一个示例,你可以使用 Stream 来过滤/

public class ReadFileLines 
    public static void main(String[] args) throws IOException 
        Stream<String> lines = Files.lines(Paths.get("C:/SelfStudy/Input.txt"));
//      System.out.println(lines.filter(str -> str.contains("SELECT")).count());

//Stream gets closed once you have run the count method.
        System.out.println(lines.parallel().filter(str -> str.contains("Delete")).count());
    

示例 input.txt。

SELECT Every thing
Delete Every thing
Delete Every thing
Delete Every thing
Delete Every thing
Delete Every thing
Delete Every thing

【讨论】:

以上是关于如何使用 Files.lines(...).forEach(...) 读取文件?的主要内容,如果未能解决你的问题,请参考以下文章

这是 Files.lines() 中的错误,还是我对并行流有误解?

Java 8流到文件[重复]

Java并行流-调用parallel()方法的顺序

Java 8 toMap IllegalStateException 重复键

java8 stream方式读取文件

如何操作使用Tuxera NTFS for Mac