Java 避免 java.lang.OutOfMemoryError 读取文件但同时使用流

Java avoid java.lang.OutOfMemoryError while reading a file but using streams at the same time

我正在尝试读取一个非常大的流文件,所以我需要并行流而不是每行迭代......我正在尝试如下:

String cont = new String(Files.readAllBytes(Paths.get(this.File_Path)),
            StandardCharsets.UTF_8);    
List<String> words = Arrays.asList(cont.split("\PL+"));

yep = words.parallelStream()
            .filter(x -> x.contains(toMatch))
            .distinct()
            .collect(Collectors.toList());

这适用于小文件大小,但如果我尝试对大小为几 gb 的文件制作相同的文件,java 会出现此异常:

java.lang.OutOfMemoryError: Required array size too large

有一种方法可以避免此异常,但同时使用并行流而不是使用 BufferReader 或 Scanner 进行迭代?

java堆内存有限。我们不能同时读取文件的全部数据。超过一定大小是不可能的(除非你增加堆内存,出于某些原因这并不理想)。我建议的是,分块读取文件,例如几行,固定大小可能为 1000 行。然后运行你的操作拆分成数组并计算那个块。
您可以通过多线程并行化块。

问题是Files.readAllBytes()。它将文件的全部内容加载到 String 中,因此在内存中。
要逐行阅读,您需要使用 Files.lines() that returns a Stream<String> 然后将其转换为并行流并对其进行转换操作:

List<String> words = 
    Files.lines(Paths.get(this.File_Path), charSetOfYourFileIfNotUTF8) // Stream<String>
         .parallel()
         .flatMap(s-> Arrays.stream(s.split("\PL+"))) // Stream<String>
         .filter(x -> x.contains(toMatch))
         .distinct()
         .collect(Collectors.toList());

关于性能,请注意 distinct() 在并行管道中使用维护顺序的收集是昂贵的。
您应该考虑 toSet() 以进一步提高性能。