Java NIO Files类(java.nio.file.Files)提供了几种操作文件系统中的文件的方法。这个Java NIO Files教程将介绍最常用的这些方法。Files类包含许多方法,所以如果您需要一个在这里没有描述的方法,那么请检查JavaDoc。Files类可能还会有一个方法来实现它。
java.nio.file.Files类与java.nio.file.Path实例一起工作,因此在处理Files类之前,您需要了解Path类。

Files.exists()

Files.exists()方法检查给定的Path在文件系统中是否存在。
可以创建在文件系统中不存在的Path实例。例如,如果您计划创建一个新目录,您首先要创建相应的Path实例,然后创建目录。
由于Path实例可能指向,也可能没有指向文件系统中存在的路径,你可以使用Files.exists()方法来确定它们是否存在(如果需要检查的话)。
这里是一个Java Files.exists()的例子:

  1. Path path = Paths.get("data/logging.properties");
  2. boolean pathExists =Files.exists(path,new LinkOption[]{ LinkOption.NOFOLLOW_LINKS});

这个例子首先创建一个Path实例指向一个路径,我们想要检查这个路径是否存在。然后,这个例子调用Files.exists()方法,然后将Path实例作为第一个参数。
注意Files.exists()方法的第二个参数。这个参数是一个选项数组,它影响Files.exists()如何确定路径是否存在。在上面的例子中的数组包含LinkOption.NOFOLLOW_LINKS,这意味着Files.exists()方法不应该在文件系统中跟踪符号链接,以确定文件是否存在。

Files.createDirectory()

Files.createDirectory()方法,用于根据Path实例创建一个新目录,下面是一个Files.createDirectory()例子:

  1. Path path = Paths.get("data/subdir");
  2. try {
  3. Path newDir = Files.createDirectory(path);
  4. } catch(FileAlreadyExistsException e){
  5. // 目录已经存在
  6. } catch (IOException e) {
  7. // 其他发生的异常
  8. e.printStackTrace();
  9. }

第一行创建表示要创建的目录的Path实例。在try-catch块中,用路径作为参数调用Files.createDirectory()方法。如果创建目录成功,将返回一个Path实例,该实例指向新创建的路径。
如果该目录已经存在,则是抛出一个java.nio.file.FileAlreadyExistsException。如果出现其他错误,可能会抛出IOException。例如,如果想要的新目录的父目录不存在,则可能会抛出IOException。父目录是您想要创建新目录的目录。因此,它表示新目录的父目录。

Files.copy()

Files.copy()方法从一个路径拷贝一个文件到另外一个目录,这里是一个Java Files.copy()例子:

  1. Path sourcePath = Paths.get("data/logging.properties");
  2. Path destinationPath = Paths.get("data/logging-copy.properties");
  3. try {
  4. Files.copy(sourcePath, destinationPath);
  5. } catch(FileAlreadyExistsException e) {
  6. // 目录已经存在
  7. } catch (IOException e) {
  8. // 其他发生的异常
  9. e.printStackTrace();
  10. }

首先,该示例创建一个源和目标Path实例。然后,这个例子调用Files.copy(),将两个Path实例作为参数传递。这可以让源路径引用的文件被复制到目标路径引用的文件中。
如果目标文件已经存在,则抛出一个java.nio.file.FileAlreadyExistsException异常。如果有其他错误,则会抛出一个IOException。例如,如果将该文件复制到不存在的目录,则会抛出IOException

重写已存在的文件

可以强制Files.copy()覆盖现有的文件。这里有一个示例,演示如何使用Files.copy()覆盖现有文件。

  1. Path sourcePath = Paths.get("data/logging.properties");
  2. Path destinationPath = Paths.get("data/logging-copy.properties");
  3. try {
  4. Files.copy(sourcePath, destinationPath,
  5. StandardCopyOption.REPLACE_EXISTING);
  6. } catch(FileAlreadyExistsException e) {
  7. // 目标文件已存在
  8. } catch (IOException e) {
  9. // 其他发生的异常
  10. e.printStackTrace();
  11. }

请注意Files.copy()方法的第三个参数。如果目标文件已经存在,这个参数指示copy()方法覆盖现有的文件。

Files.move()

Java NIO Files还包含一个函数,用于将文件从一个路径移动到另一个路径。移动文件与重命名相同,但是移动文件既可以移动到不同的目录,也可以在相同的操作中更改它的名称。是的,java.io.File类也可以使用它的renameTo()方法来完成这个操作,但是现在已经在java.nio.file.Files中有了文件移动功能。
这里有一个Java Files.move()例子:

  1. Path sourcePath = Paths.get("data/logging-copy.properties");
  2. Path destinationPath = Paths.get("data/subdir/logging-moved.properties");
  3. try {
  4. Files.move(sourcePath, destinationPath,
  5. StandardCopyOption.REPLACE_EXISTING);
  6. } catch (IOException e) {
  7. //移动文件失败
  8. e.printStackTrace();
  9. }

首先创建源路径和目标路径。源路径指向要移动的文件,而目标路径指向文件应该移动到的位置。然后调用Files.move()方法。这会导致文件被移动。
请注意传递给Files.move()的第三个参数。这个参数告诉Files.move()方法来覆盖目标路径上的任何现有文件。这个参数实际上是可选的。
如果移动文件失败,Files.move()方法可能抛出一个IOException。例如,如果一个文件已经存在于目标路径中,并且您已经排除了StandardCopyOption.REPLACE_EXISTING选项,或者被移动的文件不存在等等。

Files.delete()

Files.delete()方法可以删除一个文件或者目录。下面是一个Java Files.delete()例子:

  1. Path path = Paths.get("data/subdir/logging-moved.properties");
  2. try {
  3. Files.delete(path);
  4. } catch (IOException e) {
  5. // 删除文件失败
  6. e.printStackTrace();
  7. }

首先,创建指向要删除的文件的Path。然后调用Files.delete()方法。如果Files.delete()由于某种原因不能删除文件(例如,文件或目录不存在),会抛出一个IOException

Files.walkFileTree()

Files.walkFileTree()方法包含递归遍历目录树的功能。walkFileTree()方法将Path实例和FileVisitor作为参数。Path实例指向您想要遍历的目录。FileVisitor在遍历期间被调用。
在我解释遍历是如何工作之前,这里我们先了解FileVisitor接口:

  1. public interface FileVisitor {
  2. public FileVisitResult preVisitDirectory(
  3. Path dir, BasicFileAttributes attrs) throws IOException;
  4. public FileVisitResult visitFile(
  5. Path file, BasicFileAttributes attrs) throws IOException;
  6. public FileVisitResult visitFileFailed(
  7. Path file, IOException exc) throws IOException;
  8. public FileVisitResult postVisitDirectory(
  9. Path dir, IOException exc) throws IOException {
  10. }

您必须自己实现FileVisitor接口,并将实现的实例传递给walkFileTree()方法。在目录遍历过程中,您的FileVisitor实现的每个方法都将被调用。如果不需要实现所有这些方法,那么可以扩展SimpleFileVisitor类,它包含FileVisitor接口中所有方法的默认实现。
这里是一个walkFileTree()的例子:

  1. Files.walkFileTree(path, new FileVisitor<Path>() {
  2. @Override
  3. public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
  4. System.out.println("pre visit dir:" + dir);
  5. return FileVisitResult.CONTINUE;
  6. }
  7. @Override
  8. public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
  9. System.out.println("visit file: " + file);
  10. return FileVisitResult.CONTINUE;
  11. }
  12. @Override
  13. public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
  14. System.out.println("visit file failed: " + file);
  15. return FileVisitResult.CONTINUE;
  16. }
  17. @Override
  18. public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
  19. System.out.println("post visit directory: " + dir);
  20. return FileVisitResult.CONTINUE;
  21. }
  22. });

FileVisitor实现中的每个方法在遍历过程中的不同时间都被调用:
在访问任何目录之前调用preVisitDirectory()方法。在访问一个目录之后调用postVisitDirectory()方法。
调用visitFile()在文件遍历过程中访问的每一个文件。它不会访问目录-只会访问文件。在访问文件失败时调用visitFileFailed()方法。例如,如果您没有正确的权限,或者其他什么地方出错了。
这四个方法中的每个都返回一个FileVisitResult枚举实例。FileVisitResult枚举包含以下四个选项:

  • CONTINUE 继续
  • TERMINATE 终止
  • SKIP_SIBLING 跳过同级
  • SKIP_SUBTREE 跳过子级

通过返回其中一个值,调用方法可以决定如何继续执行文件。
CONTINUE继续意味着文件的执行应该像正常一样继续。
TERMINATE终止意味着文件遍历现在应该终止。
SKIP_SIBLINGS跳过同级意味着文件遍历应该继续,但不需要访问该文件或目录的任何同级。
SKIP_SUBTREE跳过子级意味着文件遍历应该继续,但是不需要访问这个目录中的子目录。这个值只有从preVisitDirectory()返回时才是一个函数。如果从任何其他方法返回,它将被解释为一个CONTINUE继续。

文件搜索

这里是一个用于扩展SimpleFileVisitorwalkFileTree(),以查找一个名为README.txt的文件:

  1. Path rootPath = Paths.get("data");
  2. String fileToFind = File.separator + "README.txt";
  3. try {
  4. Files.walkFileTree(rootPath, new SimpleFileVisitor<Path>() {
  5. @Override
  6. public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
  7. String fileString = file.toAbsolutePath().toString();
  8. //System.out.println("pathString = " + fileString);
  9. if(fileString.endsWith(fileToFind)){
  10. System.out.println("file found at path: " + file.toAbsolutePath());
  11. return FileVisitResult.TERMINATE;
  12. }
  13. return FileVisitResult.CONTINUE;
  14. }
  15. });
  16. } catch(IOException e){
  17. e.printStackTrace();
  18. }

递归删除目录

Files.walkFileTree()也可以用来删除包含所有文件和子目录的目录。Files.delete()方法只会删除一个目录,如果它是空的。通过遍历所有目录并删除每个目录中的所有文件(在visitFile())中,然后删除目录本身(在postVisitDirectory()中),您可以删除包含所有子目录和文件的目录。下面是一个递归目录删除示例:

  1. Path rootPath = Paths.get("data/to-delete");
  2. try {
  3. Files.walkFileTree(rootPath, new SimpleFileVisitor<Path>() {
  4. @Override
  5. public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
  6. System.out.println("delete file: " + file.toString());
  7. Files.delete(file);
  8. return FileVisitResult.CONTINUE;
  9. }
  10. @Override
  11. public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
  12. Files.delete(dir);
  13. System.out.println("delete dir: " + dir.toString());
  14. return FileVisitResult.CONTINUE;
  15. }
  16. });
  17. } catch(IOException e){
  18. e.printStackTrace();
  19. }

文件类中的其他方法

java.nio.file.Files类包含许多其他有用的函数,比如用于创建符号链接的函数、确定文件大小、设置文件权限等等。有关这些方法的更多信息,请查看java.nio.file.Files类的JavaDoc。


12人点赞

JAVA面试

作者:步积
链接:https://www.jianshu.com/p/3cb5ca04e3c8
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。Java NIO Files类(java.nio.file.Files)提供了几种操作文件系统中的文件的方法。这个Java NIO Files教程将介绍最常用的这些方法。Files类包含许多方法,所以如果您需要一个在这里没有描述的方法,那么请检查JavaDoc。Files类可能还会有一个方法来实现它。
java.nio.file.Files类与java.nio.file.Path实例一起工作,因此在处理Files类之前,您需要了解Path类。

Files.exists()

Files.exists()方法检查给定的Path在文件系统中是否存在。
可以创建在文件系统中不存在的Path实例。例如,如果您计划创建一个新目录,您首先要创建相应的Path实例,然后创建目录。
由于Path实例可能指向,也可能没有指向文件系统中存在的路径,你可以使用Files.exists()方法来确定它们是否存在(如果需要检查的话)。
这里是一个Java Files.exists()的例子:

  1. Path path = Paths.get("data/logging.properties");
  2. boolean pathExists =
  3. Files.exists(path,
  4. new LinkOption[]{ LinkOption.NOFOLLOW_LINKS});

这个例子首先创建一个Path实例指向一个路径,我们想要检查这个路径是否存在。然后,这个例子调用Files.exists()方法,然后将Path实例作为第一个参数。
注意Files.exists()方法的第二个参数。这个参数是一个选项数组,它影响Files.exists()如何确定路径是否存在。在上面的例子中的数组包含LinkOption.NOFOLLOW_LINKS,这意味着Files.exists()方法不应该在文件系统中跟踪符号链接,以确定文件是否存在。

Files.createDirectory()

Files.createDirectory()方法,用于根据Path实例创建一个新目录,下面是一个Files.createDirectory()例子:

  1. Path path = Paths.get("data/subdir");
  2. try {
  3. Path newDir = Files.createDirectory(path);
  4. } catch(FileAlreadyExistsException e){
  5. // 目录已经存在
  6. } catch (IOException e) {
  7. // 其他发生的异常
  8. e.printStackTrace();
  9. }

第一行创建表示要创建的目录的Path实例。在try-catch块中,用路径作为参数调用Files.createDirectory()方法。如果创建目录成功,将返回一个Path实例,该实例指向新创建的路径。
如果该目录已经存在,则是抛出一个java.nio.file.FileAlreadyExistsException。如果出现其他错误,可能会抛出IOException。例如,如果想要的新目录的父目录不存在,则可能会抛出IOException。父目录是您想要创建新目录的目录。因此,它表示新目录的父目录。

Files.copy()

Files.copy()方法从一个路径拷贝一个文件到另外一个目录,这里是一个Java Files.copy()例子:

  1. Path sourcePath = Paths.get("data/logging.properties");
  2. Path destinationPath = Paths.get("data/logging-copy.properties");
  3. try {
  4. Files.copy(sourcePath, destinationPath);
  5. } catch(FileAlreadyExistsException e) {
  6. // 目录已经存在
  7. } catch (IOException e) {
  8. // 其他发生的异常
  9. e.printStackTrace();
  10. }

首先,该示例创建一个源和目标Path实例。然后,这个例子调用Files.copy(),将两个Path实例作为参数传递。这可以让源路径引用的文件被复制到目标路径引用的文件中。
如果目标文件已经存在,则抛出一个java.nio.file.FileAlreadyExistsException异常。如果有其他错误,则会抛出一个IOException。例如,如果将该文件复制到不存在的目录,则会抛出IOException

重写已存在的文件

可以强制Files.copy()覆盖现有的文件。这里有一个示例,演示如何使用Files.copy()覆盖现有文件。

  1. Path sourcePath = Paths.get("data/logging.properties");
  2. Path destinationPath = Paths.get("data/logging-copy.properties");
  3. try {
  4. Files.copy(sourcePath, destinationPath,
  5. StandardCopyOption.REPLACE_EXISTING);
  6. } catch(FileAlreadyExistsException e) {
  7. // 目标文件已存在
  8. } catch (IOException e) {
  9. // 其他发生的异常
  10. e.printStackTrace();
  11. }

请注意Files.copy()方法的第三个参数。如果目标文件已经存在,这个参数指示copy()方法覆盖现有的文件。

Files.move()

Java NIO Files还包含一个函数,用于将文件从一个路径移动到另一个路径。移动文件与重命名相同,但是移动文件既可以移动到不同的目录,也可以在相同的操作中更改它的名称。是的,java.io.File类也可以使用它的renameTo()方法来完成这个操作,但是现在已经在java.nio.file.Files中有了文件移动功能。
这里有一个Java Files.move()例子:

  1. Path sourcePath = Paths.get("data/logging-copy.properties");
  2. Path destinationPath = Paths.get("data/subdir/logging-moved.properties");
  3. try {
  4. Files.move(sourcePath, destinationPath,
  5. StandardCopyOption.REPLACE_EXISTING);
  6. } catch (IOException e) {
  7. //移动文件失败
  8. e.printStackTrace();
  9. }

首先创建源路径和目标路径。源路径指向要移动的文件,而目标路径指向文件应该移动到的位置。然后调用Files.move()方法。这会导致文件被移动。
请注意传递给Files.move()的第三个参数。这个参数告诉Files.move()方法来覆盖目标路径上的任何现有文件。这个参数实际上是可选的。
如果移动文件失败,Files.move()方法可能抛出一个IOException。例如,如果一个文件已经存在于目标路径中,并且您已经排除了StandardCopyOption.REPLACE_EXISTING选项,或者被移动的文件不存在等等。

Files.delete()

Files.delete()方法可以删除一个文件或者目录。下面是一个Java Files.delete()例子:

  1. Path path = Paths.get("data/subdir/logging-moved.properties");
  2. try {
  3. Files.delete(path);
  4. } catch (IOException e) {
  5. // 删除文件失败
  6. e.printStackTrace();
  7. }

首先,创建指向要删除的文件的Path。然后调用Files.delete()方法。如果Files.delete()由于某种原因不能删除文件(例如,文件或目录不存在),会抛出一个IOException

Files.walkFileTree()

Files.walkFileTree()方法包含递归遍历目录树的功能。walkFileTree()方法将Path实例和FileVisitor作为参数。Path实例指向您想要遍历的目录。FileVisitor在遍历期间被调用。
在我解释遍历是如何工作之前,这里我们先了解FileVisitor接口:

  1. public interface FileVisitor {
  2. public FileVisitResult preVisitDirectory(
  3. Path dir, BasicFileAttributes attrs) throws IOException;
  4. public FileVisitResult visitFile(
  5. Path file, BasicFileAttributes attrs) throws IOException;
  6. public FileVisitResult visitFileFailed(
  7. Path file, IOException exc) throws IOException;
  8. public FileVisitResult postVisitDirectory(
  9. Path dir, IOException exc) throws IOException {
  10. }

您必须自己实现FileVisitor接口,并将实现的实例传递给walkFileTree()方法。在目录遍历过程中,您的FileVisitor实现的每个方法都将被调用。如果不需要实现所有这些方法,那么可以扩展SimpleFileVisitor类,它包含FileVisitor接口中所有方法的默认实现。
这里是一个walkFileTree()的例子:

  1. Files.walkFileTree(path, new FileVisitor<Path>() {
  2. @Override
  3. public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
  4. System.out.println("pre visit dir:" + dir);
  5. return FileVisitResult.CONTINUE;
  6. }
  7. @Override
  8. public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
  9. System.out.println("visit file: " + file);
  10. return FileVisitResult.CONTINUE;
  11. }
  12. @Override
  13. public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
  14. System.out.println("visit file failed: " + file);
  15. return FileVisitResult.CONTINUE;
  16. }
  17. @Override
  18. public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
  19. System.out.println("post visit directory: " + dir);
  20. return FileVisitResult.CONTINUE;
  21. }
  22. });

FileVisitor实现中的每个方法在遍历过程中的不同时间都被调用:
在访问任何目录之前调用preVisitDirectory()方法。在访问一个目录之后调用postVisitDirectory()方法。
调用visitFile()在文件遍历过程中访问的每一个文件。它不会访问目录-只会访问文件。在访问文件失败时调用visitFileFailed()方法。例如,如果您没有正确的权限,或者其他什么地方出错了。
这四个方法中的每个都返回一个FileVisitResult枚举实例。FileVisitResult枚举包含以下四个选项:

  • CONTINUE 继续
  • TERMINATE 终止
  • SKIP_SIBLING 跳过同级
  • SKIP_SUBTREE 跳过子级

通过返回其中一个值,调用方法可以决定如何继续执行文件。
CONTINUE继续意味着文件的执行应该像正常一样继续。
TERMINATE终止意味着文件遍历现在应该终止。
SKIP_SIBLINGS跳过同级意味着文件遍历应该继续,但不需要访问该文件或目录的任何同级。
SKIP_SUBTREE跳过子级意味着文件遍历应该继续,但是不需要访问这个目录中的子目录。这个值只有从preVisitDirectory()返回时才是一个函数。如果从任何其他方法返回,它将被解释为一个CONTINUE继续。

文件搜索

这里是一个用于扩展SimpleFileVisitorwalkFileTree(),以查找一个名为README.txt的文件:

  1. Path rootPath = Paths.get("data");
  2. String fileToFind = File.separator + "README.txt";
  3. try {
  4. Files.walkFileTree(rootPath, new SimpleFileVisitor<Path>() {
  5. @Override
  6. public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
  7. String fileString = file.toAbsolutePath().toString();
  8. //System.out.println("pathString = " + fileString);
  9. if(fileString.endsWith(fileToFind)){
  10. System.out.println("file found at path: " + file.toAbsolutePath());
  11. return FileVisitResult.TERMINATE;
  12. }
  13. return FileVisitResult.CONTINUE;
  14. }
  15. });
  16. } catch(IOException e){
  17. e.printStackTrace();
  18. }

递归删除目录

Files.walkFileTree()也可以用来删除包含所有文件和子目录的目录。Files.delete()方法只会删除一个目录,如果它是空的。通过遍历所有目录并删除每个目录中的所有文件(在visitFile())中,然后删除目录本身(在postVisitDirectory()中),您可以删除包含所有子目录和文件的目录。下面是一个递归目录删除示例:

  1. Path rootPath = Paths.get("data/to-delete");
  2. try {
  3. Files.walkFileTree(rootPath, new SimpleFileVisitor<Path>() {
  4. @Override
  5. public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
  6. System.out.println("delete file: " + file.toString());
  7. Files.delete(file);
  8. return FileVisitResult.CONTINUE;
  9. }
  10. @Override
  11. public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
  12. Files.delete(dir);
  13. System.out.println("delete dir: " + dir.toString());
  14. return FileVisitResult.CONTINUE;
  15. }
  16. });
  17. } catch(IOException e){
  18. e.printStackTrace();
  19. }

文件类中的其他方法

java.nio.file.Files类包含许多其他有用的函数,比如用于创建符号链接的函数、确定文件大小、设置文件权限等等。有关这些方法的更多信息,请查看java.nio.file.Files类的JavaDoc。