Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java8流通过前缀连接日志文件_Java_Java Stream - Fatal编程技术网

Java8流通过前缀连接日志文件

Java8流通过前缀连接日志文件,java,java-stream,Java,Java Stream,我有一个滚动日志文件列表,例如: thread1.2018-04-09.log thread1.2018-04-10.log thread1.2018-04-11.log thread2.2018-04-09.log thread2.2018-04-10.log thread2.2018-04-11.log 我想连接每个线程的所有日志文件,以处理这些文件,就像每个线程只有一个文件一样 我首先逐个解析所有文件: Files.newDirectoryStream(Paths.get("path/t

我有一个滚动日志文件列表,例如:

thread1.2018-04-09.log
thread1.2018-04-10.log
thread1.2018-04-11.log
thread2.2018-04-09.log
thread2.2018-04-10.log
thread2.2018-04-11.log
我想连接每个线程的所有日志文件,以处理这些文件,就像每个线程只有一个文件一样

我首先逐个解析所有文件:

Files.newDirectoryStream(Paths.get("path/to/log/folder"),
                    path -> path.toString().endsWith(".log"))
                    .forEach(this::parseLog);
然后通过手动检查生成文件的线程来合并输出。不是最优的

我可以在流操作中直接连接具有相同前缀的文件流吗

编辑:

以下是我在评论中提出的建议:

public class Test {

    public static void main(String[] args) {
        new Test().readLogs();
    }

    public void readLogs() {
        try (Stream<Path> stream = Files.list(Paths.get("."))
                .filter(path -> path.toString().endsWith(".log"))) {

            Map<String, List<Path>> pathsByThread = stream.collect(Collectors.groupingBy(this::getThreadName));

            for (String threadName : pathsByThread.keySet()) {
                pathsByThread.get(threadName).stream().flatMap(this::readAllLines).forEach(this::parseLogLine);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private String getThreadName(Path path) {
        int index = path.getFileName().toString().indexOf(".");

        return path.getFileName().toString().substring(0, index);
    }

    private Stream<String> readAllLines(Path path) {
        try (Stream<String> fileContent = Files.lines(path)) {
            return fileContent;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    private void parseLogLine(String line) {
        // Do something smart
        System.out.println(line);
    }
}

问题在于你的方法

private Stream<String> readAllLines(Path path) {
    try (Stream<String> fileContent = Files.lines(path)) {
        return fileContent;
    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}
顺便说一下,您正在
Map
keySet()
上循环,以便对每个属性执行
get
查找,只是为了仅处理值。考虑到您首先可以迭代,如果这是您唯一感兴趣的事情,那么这是非常低效的。(如果两者都需要,您可以使用)您甚至可以在此处使用流,从而将整个操作简化为:

public void readLogs() {
    try(Stream<Path> stream = Files.list(Paths.get("."))) {
        stream.filter(path -> path.toString().endsWith(".log"))
              .collect(Collectors.groupingBy(path -> {
                  final String s = path.getFileName().toString();
                  return s.substring(0, s.indexOf("."));
              }))
              .values().stream()
              .flatMap(List::stream)
              .flatMap(path -> {
                  try { return Files.lines(path); }
                  catch (IOException e) { throw new UncheckedIOException(e); }
              })
              .forEachOrdered(this::parseLogLine);
    } catch(IOException|UncheckedIOException e) {
        e.printStackTrace();
    }
}
您可以通过按整个文件名排序来简化此过程,因为这意味着按其公共前缀(包括第一个点之前的部分)排序:

public void readLogs() {
    try(Stream<Path> stream = Files.list(Paths.get("."))) {
        stream.filter(path -> path.toString().endsWith(".log"))
              .sorted(Comparator.comparing(path -> path.getFileName().toString()))
              .flatMap(path -> {
                  try { return Files.lines(path); }
                  catch (IOException e) { throw new UncheckedIOException(e); }
              })
              .forEachOrdered(this::parseLogLine);
    } catch(IOException|UncheckedIOException e) {
        e.printStackTrace();
    }
}
public void readLogs(){
try(Stream=Files.list(path.get(“.”)){
stream.filter(path->path.toString().endsWith(“.log”))
.sorted(Comparator.comparing(path->path.getFileName().toString()))
.flatMap(路径->{
尝试{返回文件.行(路径);}
catch(IOException e){抛出新的未选中的异常(e);}
})
.forEachOrdered(this::parseLogLine);
}捕获(IOException |未选中异常e){
e、 printStackTrace();
}
}

我会使用
.flatMap(Files::lines)
但是flatMap会创建一个大的行流,不是吗?我想要的是为每个线程日志提供一个行流,即一个流用于thread1.*.log,一个流用于thread2.*.logGroup首先,处理每个组..flatMap(文件::行)是不可能的,因为文件::行抛出一个无法在flatMap中捕获的IOException。请参阅编辑问题,了解如何执行此操作。如果输入是相同的文件
,则Files.lines可能返回相同的流。请注意,由于您仅使用分组来确定顺序
-
。collect(Collectors.groupingBy..)
返回一个映射,但我们不传递
mapFactory
。那么你怎么说它是用来确定顺序的呢?@user7
groupingBy
没有映射工厂并不能保证组的顺序,但是当以
.values().stream().flatMap(List::stream)
的方式在结果映射上进行流式处理时,一个组的所有元素都彼此相邻,因为这是与原始流的唯一区别,所以它只是一个排序操作,而不是一个排序,不产生总的顺序,然而,它是一个可以被排序操作替代的操作,以达到相同的效果。排序提供了比分组更强的保证,但仍然实现了OP想要的集群。谢谢。刚刚注意到OP的
路径bythread
。因此,目的是按线程名称对日志进行分组,我同意排序在这里更有意义。
public void readLogs() {
    try(Stream<Path> stream = Files.list(Paths.get("."))) {
        stream.filter(path -> path.toString().endsWith(".log"))
              .collect(Collectors.groupingBy(path -> {
                  final String s = path.getFileName().toString();
                  return s.substring(0, s.indexOf("."));
              }))
              .values().stream()
              .flatMap(List::stream)
              .flatMap(path -> {
                  try { return Files.lines(path); }
                  catch (IOException e) { throw new UncheckedIOException(e); }
              })
              .forEachOrdered(this::parseLogLine);
    } catch(IOException|UncheckedIOException e) {
        e.printStackTrace();
    }
}
public void readLogs() {
    try(Stream<Path> stream = Files.list(Paths.get("."))) {
        stream.filter(path -> path.toString().endsWith(".log"))
              .sorted(Comparator.comparing(path -> {
                  final String s = path.getFileName().toString();
                  return s.substring(0, s.indexOf("."));
              }))
              .flatMap(path -> {
                  try { return Files.lines(path); }
                  catch (IOException e) { throw new UncheckedIOException(e); }
              })
              .forEachOrdered(this::parseLogLine);
    } catch(IOException|UncheckedIOException e) {
        e.printStackTrace();
    }
}
public void readLogs() {
    try(Stream<Path> stream = Files.list(Paths.get("."))) {
        stream.filter(path -> path.toString().endsWith(".log"))
              .sorted(Comparator.comparing(path -> path.getFileName().toString()))
              .flatMap(path -> {
                  try { return Files.lines(path); }
                  catch (IOException e) { throw new UncheckedIOException(e); }
              })
              .forEachOrdered(this::parseLogLine);
    } catch(IOException|UncheckedIOException e) {
        e.printStackTrace();
    }
}