javafileiojava.nio.file

Getting an element inside a directory using java.nio.file.Path's


I am currently getting to grips with file management in Java. As far as i've read, java.nio.file.Path is the preferred way of doing so.

Say I want to copy the contents of oldDir to the, currently empty, newDir. Every time I copy a file, I need this loong line just to get the Path of newFile:

Path newDir = FileSystems.getDefault().getPath("new");
Path oldDir = FileSystems.getDefault().getPath("old");
for (Path oldFile : oldDir) {
    Path newFile = FileSystems.getDefault().getPath("new", oldFile.getFileName().toString()); // Why so complicated? :(
    Files.copy(oldFile, newFile);
}

Is there something like newDir.getChild(oldFile.getFileName()) to do what I want, or is there really no shorter way of doing it?


Solution

  • There are a couple things you can do to make the code simpler:

    1. Use Path#of(String,String...) or Paths#get(String,String...) to create your Path instances. Both methods delegate to the default FileSystem. The former was added in Java 11 and is now the preferred approach.

    2. Use Path#resolve(Path) to append a relative path to some absolute path.

    But there's also an error in your code. You are iterating over oldDir which works because Path implements Iterable<Path>. However, that iterates over the names of the path, not the children of the path. In other words, this:

    Path path = Path.of("foo", "bar", "file.txt");
    for (Path name : path) {
      System.out.println(name);
    }
    

    Will output:

    foo
    bar
    file.txt
    

    If you want to iterate over the children of a directory you need to use something like Files#list(Path) or Files#newDirectoryStream(Path) (the latter has two overloads). Both those methods only return the immediate children of the directory. There are other methods available to recursively iterate a directory and its sub-directories; browse the Files documentation to see what's provided.

    So your code should instead look something like:

    Path oldDir = Path.of(...);
    Path newDir = Path.of(...);
    try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(oldDir)) {
      for (Path oldFile : dirStream) {
        Path newFile = newDir.resolve(oldFile.getFileName());
        Files.copy(oldFile, newFile);
      }
    }