Reprint the use of Files class in Java NIO

Posted by barryflood22 on Fri, 11 Feb 2022 10:25:24 +0100

The files class in Java NIO (java.nio.file.Files) provides a variety of methods to operate files in the file system.

Files.exists()

Files. The exits () method is used to check whether the given Path exists in the file system. It is feasible to create a Payh that does not exist in the file system. For example, if you want to create a new directory, create the corresponding Path instance and then create a directory.

Since the Path instance may point to a Path that does not exist in the file system, you need to use files Exists() to confirm.

The following is an example using files Examples of exists():

Path path = Paths.get("data/logging.properties");

boolean pathExists =
        Files.exists(path,
            new LinkOption[]{ LinkOption.NOFOLLOW_LINKS});

In this example, we first create a Path object, and then use files Exists() to check whether the Path really exists.

Note files The second parameter of exists(). It is an array, and this parameter directly affects files How exists() determines whether a path exists. In this case, the array contains linkoptions NOFOLLOW_ Links, which means that the symbolic link file is not included in the detection.

Files.createDirectory()

Files.createDirectory() will create the Path represented by Path. Here is an example:

Path path = Paths.get("data/subdir");

try {
    Path newDir = Files.createDirectory(path);
} catch(FileAlreadyExistsException e){
    // the directory already exists.
} catch (IOException e) {
    //something else went wrong
    e.printStackTrace();
}

The first line creates a Path instance that represents the directory to be created. Then try catch the files The call to createdirectory() caught. If the creation is successful, the return value is the newly created Path.

If the directory already exists, a Java. Net will be thrown nio. file. Filealreadyexistexception exception. If there are other problems, an IOException will be thrown. For example, if the parent directory of the directory to be created does not exist, IOException will be thrown. The parent directory refers to the location of the directory you want to create. That is, the parent directory of the newly created directory.

Files.copy()

Files. The copy () method can copy a file from one address to another. For example:

Path sourcePath      = Paths.get("data/logging.properties");
Path destinationPath = Paths.get("data/logging-copy.properties");

try {
    Files.copy(sourcePath, destinationPath);
} catch(FileAlreadyExistsException e) {
    //destination file already exists
} catch (IOException e) {
    //something else went wrong
    e.printStackTrace();
}

In this example, first create the Path instance of the original file and the target file. Then pass them as parameters to files Copy (), and then the file will be copied.

If the target file already exists, it will throw Java nio. file. Filealreadyexistsexception exception. Similarly, if an error occurs in the middle of spitting, IOException will also be thrown.

Overwriting existing files

The copy operation can force the existing target file to be overwritten. The following is a specific example:

Path sourcePath      = Paths.get("data/logging.properties");
Path destinationPath = Paths.get("data/logging-copy.properties");

try {
    Files.copy(sourcePath, destinationPath,
            StandardCopyOption.REPLACE_EXISTING);
} catch(FileAlreadyExistsException e) {
    //destination file already exists
} catch (IOException e) {
    //something else went wrong
    e.printStackTrace();
}

Note the third parameter of the copy method, which determines whether the file can be overwritten.

Files.move()

The Files class of Java NIO also contains the interface of mobile Files. Moving a file is the same as renaming, but it also changes the directory location of the file. java. io. The function of the renameTo() method in the file class is the same.

Path sourcePath      = Paths.get("data/logging-copy.properties");
Path destinationPath = Paths.get("data/subdir/logging-moved.properties");

try {
    Files.move(sourcePath, destinationPath,
            StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
    //moving file failed.
    e.printStackTrace();
}

First, create the source path and target path. The original path refers to the initial path of the file to be moved, and the target path refers to the location to be moved.

Here, the third parameter of move also allows us to overwrite existing files.

Files.delete()

Files. The delete () method can delete a file or directory:

Path path = Paths.get("data/subdir/logging-moved.properties");

try {
    Files.delete(path);
} catch (IOException e) {
    //deleting file failed
    e.printStackTrace();
}

First, create the path object of the file to be deleted. Then you can call delete.

Files.walkFileTree()

Files. The walkFileTree () method has the function of recursively traversing directories. walkFileTree accepts a Path and FileVisitor as parameters. The Path object is the directory that needs to be traversed, and FileVistor will be called in each traversal.

Let's take a look at the definition of the FileVisitor interface:

public interface FileVisitor {

    public FileVisitResult preVisitDirectory(
        Path dir, BasicFileAttributes attrs) throws IOException;

    public FileVisitResult visitFile(
        Path file, BasicFileAttributes attrs) throws IOException;

    public FileVisitResult visitFileFailed(
        Path file, IOException exc) throws IOException;

    public FileVisitResult postVisitDirectory(
        Path dir, IOException exc) throws IOException {

}

FileVisitor needs to be implemented by the caller, and then passed into walkfiletree () as a parameter Each method of FileVisitor will be called multiple times during traversal. If you don't need to handle each method, you can inherit its default implementation class SimpleFileVisitor, which makes all interfaces null.

Here is an example of walkFileTree():

Files.walkFileTree(path, new FileVisitor<Path>() {
  @Override
  public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
    System.out.println("pre visit dir:" + dir);
    return FileVisitResult.CONTINUE;
  }

  @Override
  public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
    System.out.println("visit file: " + file);
    return FileVisitResult.CONTINUE;
  }

  @Override
  public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
    System.out.println("visit file failed: " + file);
    return FileVisitResult.CONTINUE;
  }

  @Override
  public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
    System.out.println("post visit directory: " + dir);
    return FileVisitResult.CONTINUE;
  }
});

The FileVisitor method will be called at different times: preVisitDirectory() is called before accessing the directory. postVisitDirectory() is called after access.

visitFile() will be called every time the file is accessed throughout the traversal. It's not about directories, it's about files. visitFileFailed() is called when the file access fails. For example, when there is a lack of appropriate permissions or other errors.

The above four methods all return a FileVisitResult enumeration object. Specific optional enumeration items include:

  • CONTINUE
  • TERMINATE
  • SKIP_SIBLINGS
  • SKIP_SUBTREE

Returning this enumeration value allows the caller to decide whether the file traversal needs to continue. Continue indicates that the file traversal continues as normal.

TERMINATE indicates that file access needs to be terminated.

SKIP_SIBLINGS indicates that file access continues, but no other sibling files or directories need to be accessed.

SKIP_SUBTREE means to continue to access, but you do not need to access the subdirectories under this directory. This enumeration value is valid only when returned in preVisitDirectory(). If returned in several other methods, it will be understood as continue.

Searching For Files

Let's look for an example through readme. Tree() Txt file:

Path rootPath = Paths.get("data");
String fileToFind = File.separator + "README.txt";

try {
  Files.walkFileTree(rootPath, new SimpleFileVisitor<Path>() {

    @Override
    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
      String fileString = file.toAbsolutePath().toString();
      //System.out.println("pathString = " + fileString);

      if(fileString.endsWith(fileToFind)){
        System.out.println("file found at path: " + file.toAbsolutePath());
        return FileVisitResult.TERMINATE;
      }
      return FileVisitResult.CONTINUE;
    }
  });
} catch(IOException e){
    e.printStackTrace();
}

Deleting Directies Recursively

Files.walkFileTree() can also be used to delete a directory and all internal files and subitems. Files.delete() is only used to delete an empty directory. We traverse the directory, then all the files in the visitFile() interface three times, and finally delete the directory itself in postVisitDirectory().

Path rootPath = Paths.get("data/to-delete");

try {
  Files.walkFileTree(rootPath, new SimpleFileVisitor<Path>() {
    @Override
    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
      System.out.println("delete file: " + file.toString());
      Files.delete(file);
      return FileVisitResult.CONTINUE;
    }

    @Override
    public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
      Files.delete(dir);
      System.out.println("delete dir: " + dir.toString());
      return FileVisitResult.CONTINUE;
    }
  });
} catch(IOException e){
  e.printStackTrace();
}