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()
以进一步提高性能。
我正在尝试读取一个非常大的流文件,所以我需要并行流而不是每行迭代......我正在尝试如下:
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()
以进一步提高性能。