所以,我有多个txt文件,比如txt1,txt2,...
,每行有一些4到22个字符的文本,我有另一个具有相似值的txt文件,比如说bigText
。目标是检查bigTxt
中出现在任何txt文件中某处的所有值并输出这些值(我们确保bigTxt
中的任何一行都在任何一个txt文件,与该行匹配只发生一次)。到目前为止,我所拥有的最佳解决方案是有效的,但效率稍低。基本上,它看起来像这样:
txtFiles.parallelStream().forEach(file->{
List<String> txtList = listOfLines of this txtFile;
streamOfLinesOfBigTxt.forEach(line->{
if(txtList.contains(line)){
System.out.println(line);
//it'd be great if we could just stop this forEach loop here
//but that seems hardish
}
});
});
(注意:我尝试使用Honza&#34;错误的想法&#34;解决方案来解决forEach:Break or return from Java 8 stream forEach?但这必须做一些不是我的事情想要,因为它实际上使代码通常有点慢或大致相同)
这个问题的一个小问题是,即使一个文件找到了bigTxt
文件和其他txt文件之间的一条线的匹配,其他txt文件仍然会尝试搜索该行的检查(即使我们&已经找到了一场比赛并且足够了。我试图阻止这一点的事情是首先迭代bigTxt行(不是并行,但是并行浏览每个txt文件)并使用java&#39; s anyMatch
我得到了一个&#34;流已被修改或关闭&#34;我后面理解的错误类型是因为anyMatch
正在终止。因此,在其中一个txt文件的其中一行上只调用一次anyMatch
之后,该流将不再可供我稍后处理。我无法想出正确使用findAny
的方法,我也不认为allMatch
是我想要的,因为bigTxt
的所有值都不一定在其中一个txt文件。任何(并行)解决方案(甚至不严格包括Java 8中的内容)都是受欢迎的。谢谢。
答案 0 :(得分:3)
如果streamOfLinesOfBigTxt
是Stream
,则您在问题中发布的代码会出现同样的错误,因为您尝试使用外部流forEach
多次处理该流。目前尚不清楚为什么你没有注意到这一点,但也许你总是在程序开始处理第二个文件之前就停止了它?毕竟,为大文件的每一行线性搜索List
行所需的时间与两行数的乘积成比例。
当你说,你想“检查任何txt文件中某处出现的bigTxt中的所有值并输出这些值”时,你可以直截了当地做到这一点:
Files.lines(Paths.get(bigFileLocation))
.filter(line -> txtFiles.stream()
.flatMap(path -> {
try { return Files.lines(Paths.get(path)); }
catch (IOException ex) { throw new UncheckedIOException(ex); }
})
.anyMatch(Predicate.isEqual(line)) )
.forEach(System.out::println);
这会造成短路,但仍然存在与n×m
一致的处理时间问题。更糟糕的是,它会重复打开并反复读取txtfiles。
如果您想避免这种情况,将数据存储在RAM中是不可避免的。如果存储它们,您可以选择一个支持优于线性查找的存储:
Set<String> matchLines = txtFiles.stream()
.flatMap(path -> {
try { return Files.lines(Paths.get(path)); }
catch (IOException ex) { throw new UncheckedIOException(ex); }
})
.collect(Collectors.toSet());
Files.lines(Paths.get(bigFileLocation))
.filter(matchLines::contains)
.forEach(System.out::println);
现在,它的执行时间与所有文件的行数而不是产品的总和成比例。但它需要临时存储txtFiles
的所有不同行。
如果大文件的明显行数少于其他文件并且顺序无关紧要,则将大文件的行存储在一个集合中,然后检查txtFiles
的行
Set<String> matchLines
= Files.lines(Paths.get(bigFileLocation)).collect(Collectors.toSet());
txtFiles.stream()
.flatMap(path -> {
try { return Files.lines(Paths.get(path)); }
catch (IOException ex) { throw new UncheckedIOException(ex); }
})
.filter(matchLines::contains)
.forEach(System.out::println);
这依赖于所有匹配行在所有这些文本文件中都是唯一的属性,正如您在问题中所述。
我不认为,这里的并行处理会带来任何好处,因为I / O速度将主导执行。