【问题标题】:Java 8 - get a Map of parent directory and list of subdirectoriesJava 8 - 获取父目录和子目录列表的地图
【发布时间】:2021-10-04 18:46:00
【问题描述】:

我有一个这样的文件夹结构:

/home/user/root/
                dir1/
                     subDir1/
                             pdf1.pdf
                             log1.log
                     subDir2/
                             somefile.txt
                     subDir3
                dir2/
                     subDir1
                     subDir4
                     subDir5
                abc.txt
                def.pdf
                xyz.log

等等

我的要求是给定输入路径“/home/user/root/”,得到一个Map<String, List<String>>,如下:

key: dir1, value: [subDir1, subDir2, subDir3]
key: dir2, value: [subDir1, subDir4, subDir5]
...
...

也就是说,地图的键是给定输入下的第一级目录,然后每个键都有一个值,即第一级下的子目录列表。

我可以获得一级目录的列表:

private Set<String> listFilesUsingFileWalk(String rootDir, int depth) throws IOException {
        Path path = Paths.get(rootDir);
        try (Stream<Path> stream = Files.walk(path, depth)) {
            return stream
                    .filter(file -> Files.isDirectory(file) && !file.equals(path))
                    .map(Path::getFileName)
                    //.forEach(d -> System.out.println(d.getFileName()));
                    .map(Path::toString)
                    .collect(Collectors.toSet());
        }
    }

但无法获得所需的输出。我认为递归可能是一种解决方案,但不能从 Java 8 流的角度考虑。

请问可以告知一下吗?

【问题讨论】:

  • 深度是什么意思?在您的要求中,您仅将第一级作为键,将第二级作为值。那么,它总是那么深吗?
  • depth 对于 dir1、dir2 等为 1,对于 subDir1、subDir2 等为 2(从根目录)
  • 子目录名不可能是父目录吗?
  • 没有。根目录下的rootparentDir 和 parentDir 下的subDirs 将始终具有不同的名称

标签: collections java-8 java-stream


【解决方案1】:

我仍然不确定您的深度参数的用途。但看起来你正在寻找这样的东西:

private Map<String,List<String>> listFilesUsingFileWalk(String rootDir, int depth) throws IOException {
        Path path = Paths.get(rootDir);
        try (Stream<Path> stream = Files.walk(path, depth)) {
            return stream
                    .filter(file -> Files.isDirectory(file) && !file.equals(path))
                    .collect(Collectors.toMap(
                            (p) -> p.getFileName().toString(),
                            (p) -> Arrays.stream(p.toFile().listFiles()).filter(File::isDirectory).map(File::getName).collect(Collectors.toList())
                    ));
        }
}

或(不使用 File 类)

private Map<String,List<String>> listFilesUsingFileWalk(String rootDir, int depth) throws IOException {
        Path path = Paths.get(rootDir);
        try (Stream<Path> stream = Files.walk(path, depth)) {
            return stream
                    .filter(file -> Files.isDirectory(file) && !file.equals(path))
                    .collect(Collectors.toMap(
                            (p) -> p.getFileName().toString(),
                            (p) -> {
                                try {
                                    return Files.list(p).filter(Files::isDirectory).map(Path::getFileName).map(Path::toString).collect(Collectors.toList());
                                } catch (IOException e) {
                                    return Collections.emptyList();
                                }
                            }
                    ));
        }
}

【讨论】:

    【解决方案2】:

    由于您的目录名称是唯一的,因此您可以采用这种方法。 你也不需要递归

    Map<String, List<String>> collect = stream
                    .filter(file -> Files.isDirectory(file) && !file.equals(path))
                    .filter(file -> !file.getParent().equals(path))
                    .collect(Collectors.groupingBy(p -> p.getParent().getFileName().toString(), Collectors.mapping(p -> p.getFileName().toString(), Collectors.toList())));
    

    注意:这将为您提供所有父子目录。

    private Map<String, List<String>> listFilesUsingFileWalk(String rootDir, int depth) throws IOException {
        Path path = Paths.get(rootDir);
        Stream<Path> stream = Files.walk(path, depth);
        return stream
                    .filter(file -> Files.isDirectory(file) && !file.equals(path))
                    .filter(file -> !file.getParent().equals(path))
                    .collect(Collectors.groupingBy(p -> p.getParent().getFileName().toString(), Collectors.mapping(p -> p.getFileName().toString(), Collectors.toList())));
    }
    

    【讨论】:

    • 嗨,Ray,这个解决方案给我的输出类似于我的代码产生的输出:{rootDir=[dir1, dir2]}。但是,来自 dajavx 的代码提供了所需的输出。感谢您的回复。
    • @curious_brain 我已经更新了我的答案以满足您的要求
    猜你喜欢
    • 1970-01-01
    • 2018-07-15
    • 1970-01-01
    • 2013-11-18
    • 2017-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-01
    相关资源
    最近更新 更多