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
。那么你怎么说它是用来确定顺序的呢?@user7groupingBy
没有映射工厂并不能保证组的顺序,但是当以.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();
}
}