【问题标题】:Is there any way for reading two or more files in one Java8-stream?有没有办法在一个 Java8 流中读取两个或多个文件?
【发布时间】:2015-04-17 05:39:32
【问题描述】:

我喜欢新的 Java8 StreamAPI,并且希望它不仅仅用于一个文件。 像往常一样,我使用以下代码:

Stream<String> lines = Files.lines(Paths.get("/somepathtofile"));

但是如果可能的话,如何在一个流中读取两个文件呢?

【问题讨论】:

  • 我看不出它的意义所在。这两个文件将有不同的行数。当您阅读另一个时,一个可能会克服。你的用例是什么?
  • @jatin ,我有每天轮换的日志文件。我需要解析过去 24 小时内的所有日志。我想要两个日志文件(今天和昨天)将它们放在一个流中并应用“过滤器”功能。
  • 您的意思是来自两个文件的流具有相同的时间戳?
  • 是的,但在同一时间范围内。过去 24 小时的日志条目可能在今天的日志文件(2015-04-17 12:09)和昨天的日志(2015-04-16 23:55)中

标签: java file-io java-8 java-stream


【解决方案1】:

没有任何额外的辅助函数或外部库,最简单的是:

Stream<String> lines1 = Files.lines(Paths.get("/somepathtofile"));
Stream<String> lines2 = Files.lines(Paths.get("/somepathtoanotherfile"));

Stream.concat(lines1, lines)
    .filter(...)
    .forEach(...);

如果Files.lines 没有被声明为抛出检查异常,你可以这样做

Stream.of("/file1", "/file2")
     .map(Paths::get)
     .flatMap(Files::lines)....

但是,唉,我们不能那样做。有几种解决方法。一种是创建自己的Files.lines 版本,它调用标准版本,捕获IOException 并重新抛出UncheckedIOException。另一种方法是一种更通用的方法,可以用抛出检查异常的方法来制作函数。它看起来像这样:

@FunctionalInterface
public interface ThrowingFunction<T,R> extends Function<T,R> {

    @Override
    public default R apply(T t) {
        try {
            return throwingApply(t);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static<T,R> Function<T,R> wrap(ThrowingFunction<T,R> f) {
        return f;
    }

    R throwingApply(T t) throws Exception;
}

然后

Stream.of("/somefile", "/someotherfile", "/yetanotherfile")
        .map(Paths::get)
        .flatMap(ThrowingFunction.wrap(Files::lines))
        .....

有几个库经历了为每个功能接口编写类似上述内容的麻烦。

【讨论】:

  • 哦,谢谢。我尝试在 streamAPI 源中发现类似这样的东西,但失败了
  • 你很棒,但可以告诉我这种方式比简单的 public static Stream ownlines(Path path) { try { return Files.lines(path); } catch (IOException e) { e.printStackTrace(); } 返回空值; }
  • @mechanikos return null 不好。而是使用try {return Files.lines(p);} catch (IOException e) { throw new UncheckedIOException(e);}
  • 没有好坏之分。这不一样。如果您发现自己经常遇到带有检查异常的类似问题,您可能应该使用可以在任何地方应用的通用解决方案。如果只是这一次,也许适度的解决方案更合适。无论您感觉如何,都可以让您的代码更易于遵循。
【解决方案2】:

您可以使用以下代码

Files.list(Paths.get("path"))
            .filter(Files::isRegularFile)
            .flatMap(s -> {
                try {
                    return Files.lines(s);
                } catch (IOException e) {
                    e.printStackTrace();
                }
                return null;
            })
            .forEach(System.out::println);

【讨论】:

    【解决方案3】:

    使用cyclops-streams(我们创建的库)您可以编写

      SequenceM.of("/somepathtofile1","/somepathtofile2")
                 .flatMapFile(File::new)
                 .forEach(System.out::println);
    

    JavadocSequenceM 扩展了 java.util.stream.Stream(以及 org.jooq.lambda.Seq)以添加许多额外的便利方法。

    【讨论】:

      猜你喜欢
      • 2021-08-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-05
      • 1970-01-01
      • 1970-01-01
      • 2015-03-05
      相关资源
      最近更新 更多