我了解如何使用 Java 8 Streams 从文件中获取特定数据。例如,如果我们需要从这样的文件中获取加载的包
2015-01-06 11:33:03 b.s.d.task [INFO] Emitting: eVentToRequestsBolt __ack_ack
2015-01-06 11:33:03 c.s.p.d.PackagesProvider [INFO] ===---> Loaded package com.foo.bar
2015-01-06 11:33:04 b.s.d.executor [INFO] Processing received message source: eventToManageBolt:2, stream: __ack_ack, id: {}, [-6722594615019711369 -1335723027906100557]
2015-01-06 11:33:04 c.s.p.d.PackagesProvider [INFO] ===---> Loaded package co.il.boo
2015-01-06 11:33:04 c.s.p.d.PackagesProvider [INFO] ===---> Loaded package dot.org.biz
我们能做到
List<String> packageList = Files.lines(Paths.get(args[1])).filter(line -> line.contains("===---> Loaded package"))
.map(line -> line.split(" "))
.map(arr -> arr[arr.length - 1]).collect(Collectors.toList());
我从 Parsing File Example 获取(并稍微修改)了代码.
但是,如果我们还需要从同一日志文件中获取Emitting:事件的所有日期(和时间)怎么办?我们如何在使用同一个流的情况下做到这一点?
我只能想象使用 collect(groupingBy(...))
将带有 Loaded packages 的行和带有 Emitting: 的行分组解析,然后分别解析每个组(一个映射条目)。但这会使用日志文件中的所有原始数据创建一个 map ,这非常消耗内存。
是否有类似的方法可以有效地从 Java 8 Streams 中提取多种类型的数据?
最佳答案
您可以解决这个问题,而无需定义新的收集器并以更命令式的方式使用第三方库。首先,您需要定义一个表示解析结果的类。它应该有两种方法来接受输入行并与现有的部分结果结合:
class Data {
List<String> packageDates = new ArrayList<>();
List<String> emittingDates = new ArrayList<>();
// Consume single input line
void accept(String line) {
if(line.contains("===---> Loaded package"))
packageDates.add(line.substring(0, "XXXX-XX-XX".length()));
if(line.contains("Emitting"))
packageDates.add(line.substring(0, "XXXX-XX-XX XX:XX:XX".length()));
}
// Combine two partial results
void combine(Data other) {
packageDates.addAll(other.packageDates);
emittingDates.addAll(other.emittingDates);
}
}
现在您可以通过非常简单的方式收集:
Data result = Files.lines(Paths.get(args[1]))
.collect(Data::new, Data::accept, Data::combine);
关于java - 如何使用 Java Stream API 有效解析文本文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34884439/