如何使用Files.walk()...根据条件获取文件图表?

时间:2015-04-11 04:36:18

标签: java java-8

我有以下目录结构:

/path/to/stuff/org/foo/bar/
/path/to/stuff/org/foo/bar/1.2.3/
/path/to/stuff/org/foo/bar/1.2.3/myfile.ext
/path/to/stuff/org/foo/bar/1.2.4/
/path/to/stuff/org/foo/bar/1.2.4/myfile.ext
/path/to/stuff/org/foo/bar/blah/
/path/to/stuff/org/foo/bar/blah/2.1/
/path/to/stuff/org/foo/bar/blah/2.1/myfile.ext
/path/to/stuff/org/foo/bar/blah/2.2/
/path/to/stuff/org/foo/bar/blah/2.2/myfile.ext

我想得到以下输出:

/path/to/stuff/org/foo/bar/
/path/to/stuff/org/foo/bar/blah/

我有以下代码(下面),这是低效的,因为它打印出来:

/path/to/stuff/org/foo/bar/
/path/to/stuff/org/foo/bar/
/path/to/stuff/org/foo/bar/blah/
/path/to/stuff/org/foo/bar/blah/

这是Java代码:

public class LocatorTest
{

    @Test
    public void testLocateDirectories()
            throws IOException
    {
        long startTime = System.currentTimeMillis();

        Files.walk(Paths.get("/path/to/stuff/"))
             .filter(Files::isDirectory)
             .forEach(Foo::printIfArtifactVersionDirectory);

        long endTime = System.currentTimeMillis();

        System.out.println("Executed in " + (endTime - startTime) + " ms.");
    }

    static class Foo
    {

        static void printIfArtifactVersionDirectory(Path path)
        {
            File f = path.toAbsolutePath().toFile();
            List<String> filePaths = Arrays.asList(f.list(new MyExtFilenameFilter()));

            if (!filePaths.isEmpty())
            {
                System.out.println(path.getParent());
            }
        }

    }

}

过滤器:

public class MyExtFilenameFilter
        implements FilenameFilter
{

    @Override
    public boolean accept(File dir, String name)
    {
        return name.endsWith(".ext");
    }

}

3 个答案:

答案 0 :(得分:34)

Files.walk(Paths.get("/path/to/stuff/"))
     .filter(p -> p.toString().endsWith(".ext"))
     .map(p -> p.getParent().getParent())
     .distinct()
     .forEach(System.out::println);

这将过滤所有具有扩展名的文件并获取其目录的父路径。 distinct确保每个路径仅使用一次。

答案 1 :(得分:4)

您正在为所有访问过的目录调用方法printIfArtifactVersionDirectory。我做了一点改变,显而易见:

static void printIfArtifactVersionDirectory(Path path) {
    System.out.println("--- " + path);
    ...
}

有了这个额外的输出,你将得到:

  

--- C:\ Projects \ stuff
  --- C:\ Projects \ stuff \ org
  --- C:\ Projects \ stuff \ org \ foo
  --- C:\ Projects \ stuff \ org \ foo \ bar
  --- C:\ Projects \ stuff \ org \ foo \ bar \ 1.2.3
  C:\项目\东西\组织\富\酒吧
  --- C:\ Projects \ stuff \ org \ foo \ bar \ 1.2.4
  C:\项目\东西\组织\富\酒吧
  --- C:\ Projects \ stuff \ org \ foo \ bar \ blah
  --- C:\ Projects \ stuff \ org \ foo \ bar \ blah \ 2.1
  C:\项目\东西\组织\富\酒吧\等等
  --- C:\ Projects \ stuff \ org \ foo \ bar \ blah \ 2.2
  C:\ Projects \ stuff \ org \ foo \ bar \ blah

因此,您可以像拥有工件版本目录一样获得输出。如果您想记住您已经为一个目录输出了输出,那么您必须在某处存储此信息。一个快速实施可能是:

static class Foo {
    private static final Set<Path> visited = new HashSet<>();

    static void printIfArtifactVersionDirectory(Path path) {
        ...
        Path parent = path.getParent();
        if (!filePaths.isEmpty() && !visited.contains(parent)) {
            visited.add(parent);
            System.out.println(parent);
        }
    }
}

通过这个,您可以获得预期的输出:

  

C:\项目\东西\有机\ FOO \酒吧
  C:\ Projects \ stuff \ org \ foo \ bar \ blah

更好的解决方案是使用该集来存储访问过的父母,并且只有在访问所有父母后才能打印

static class PathStore {
    private final Set<Path> store = new HashSet<>();

    void visit(Path path) {
        File f = path.toAbsolutePath().toFile();
        List<String> filePaths = Arrays.asList(f.list(new MyExtFilenameFilter()));
        if (!filePaths.isEmpty()) {
            store.add(path.getParent());
        }
    }

    void print() {
        store.forEach(System.out::println);
    }
}

用法:

PathStore pathStore = new PathStore();
Files.walk(Paths.get("/path/to/stuff/"))
        .filter(Files::isDirectory)
        .forEach(pathStore::visit);
pathStore.print();

答案 2 :(得分:1)

添加到@a-better-oliver's answer中,这是如果您的操作声明IOExceptions可以执行的操作。

您可以将过滤后的流视为<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <ul> <li> <input type="checkbox" class="check-negozio" data-npv="0"> <ul> <li class="nav-item"> <input type="checkbox" class="check-cassa" data-cs="1"> </li> <li> <input type="checkbox" class="check-cassa" data-cs="5"> <ul> <li> <input type="checkbox" class="check-operatore" data-op="0"> </li> </ul> </li> </ul> </li> </ul>,然后在常规的for-each循环中执行操作。这样,您不必在lambda内部处理异常。

Iterable

在这里找到了诀窍:https://stackoverflow.com/a/32668807/1207791