java - 如何使用 Java Stream API 有效解析文本文件

标签 java java-8 java-stream

我了解如何使用 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/

相关文章:

java - 在 java 中执行 linux 终端命令?

java - 使用 ElasticSearch Java API 模糊查询日期

java - 如何停止/解决 Java 应用程序在 Linux 窗口管理器中窃取焦点

java - 将 pojo 列表合并到可以在键上组合的整数 Map

java - 在 For each 中使用 Lambda 和 Streams 并返回结果

api - 获取与文件修订相关的日期和描述 - Java API Perforce

java - Java 8 方法引用中的混淆,用于使用 BiPredicate 实现 equals 方法

java - 了解 Java 8 Lambda 表达式

Java 8代码优化——删除if语句

java - java中是否有最简单的reduce/fold方法?