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

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


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());

这适用于小文件大小,但如果我尝试对具有一些 gbs 大小的文件进行相同操作,java 会给我这个异常:


java.lang.OutOfMemoryError: Required array size too large

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


跃然一笑
浏览 150回答 2
2回答

婷婷同学_

问题是Files.readAllBytes()。它将文件的全部内容加载到 a 中String,因此在内存中。要逐行读取,您要使用Files.lines()它返回 aStream<String>然后将其转换为并行流并对它进行转换操作:List<String>&nbsp;words&nbsp;=&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;Files.lines(Paths.get(this.File_Path),&nbsp;charSetOfYourFileIfNotUTF8)&nbsp;//&nbsp;Stream<String> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.parallel() &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.flatMap(s->&nbsp;Arrays.stream(s.split("\\PL+")))&nbsp;//&nbsp;Stream<String> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.filter(x&nbsp;->&nbsp;x.contains(toMatch)) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.distinct() &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.collect(Collectors.toList());关于性能,请注意distinct()在并行管道中使用维护顺序的收集是昂贵的。您应该考虑toSet()进一步提高性能。

守着星空守着你

java 堆内存是有限的。我们不能同时读取文件的全部数据。超过一定大小是不可能的(除非你增加堆内存,出于某些原因这并不理想)。我建议的是,分块读取文件,例如几行,固定大小可能为 1000 行。然后运行拆分为数组并计算该块的操作。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java