有没有办法在一个Java8流中读取两个或多个文件?
我喜欢新的Java8 StreamAPI,并且不仅要将它用于一个文件。 通常,我使用此代码:
Stream lines = Files.lines(Paths.get("/somepathtofile"));
但如果可能的话,如何在一个流中读取两个文件?
没有任何额外的辅助函数或外部库,最简单的是:
Stream lines1 = Files.lines(Paths.get("/somepathtofile")); Stream lines2 = Files.lines(Paths.get("/somepathtoanotherfile")); Stream.concat(lines1, lines) .filter(...) .forEach(...);
如果没有声明Files.lines
抛出一个已检查的exception,那么你就能做到
Stream.of("/file1", "/file2") .map(Paths::get) .flatMap(Files::lines)....
但是,唉,我们做不到。 有几种解决方法。 一种是创建自己的Files.lines
版本,调用标准版本,捕获IOException
并重新呈现为UncheckedIOException
。 另一种方法是使用抛出已检查exception的方法生成函数的更通用方法。 它看起来像这样:
@FunctionalInterface public interface ThrowingFunction extends Function { @Override public default R apply(T t) { try { return throwingApply(t); } catch (Exception e) { throw new RuntimeException(e); } } public static Function wrap(ThrowingFunction f) { return f; } R throwingApply(T t) throws Exception; }
接着
Stream.of("/somefile", "/someotherfile", "/yetanotherfile") .map(Paths::get) .flatMap(ThrowingFunction.wrap(Files::lines)) .....
有几个库经历了为每个function界面编写类似上面的东西的麻烦。
使用cyclops-streams (我们创建的库),您可以编写
SequenceM.of("/somepathtofile1","/somepathtofile2") .flatMapFile(File::new) .forEach(System.out::println);
Javadoc SequenceM扩展了java.util.stream.Stream(以及org.jooq.lambda.Seq)以添加许多其他便利方法。
您可以使用以下代码
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);