Java NIO Files

java.nio.file.Files类提供了许多操作文件的方法,它们往往和Path类合作使用。

Files#exits()方法检查一个Path是否存在于当前的文件系统中。假如我们直接使用Path实例的相关方法,那么一个不存在的文件可能会被创建,如果我们想避免这种情况的发生,那么可以先使用Files#extis()来进行一下检查。

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

显然,exits()方法有两个参数,第一个是要检查的path,第二个是exits()方法的选项数组。如LinkOption.NOFOLLOW_LINKS代表不允许跟随文件系统中的符号链接来确定路径是否存在。

Files#createDirectory()方法利用Path创建一个新的目录。

  1. Path path = Paths.get("data/subdir");
  2. try {
  3. Path newDir = Files.createDirectory(path);
  4. } catch(FileAlreadyExistsException e){
  5. // the directory already exists.
  6. } catch (IOException e) {
  7. //something else went wrong
  8. e.printStackTrace();
  9. }

通过上面的示例一眼就可以看出这个方法是干嘛用的,另外就是注意一下通过抛出异常来对不同的情况进行处理。

注:假如父目录不存在,可能抛出IOException异常。

Files#copy()方法将文件从一个path复制到另一个。

  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. //destination file already exists
  7. } catch (IOException e) {
  8. //something else went wrong
  9. e.printStackTrace();
  10. }

功能太明显了。如果目标文件已存在,会抛出FileAlreadyExistsException,如果试图将文件复制到不存在的目录,会抛出IOException

但也可以要求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. //destination file already exists
  8. } catch (IOException e) {
  9. //something else went wrong
  10. e.printStackTrace();
  11. }

在copy方法的参数列表中加上这个StandardCopyOption.REPLACE_EXISTING,可以在目标文件存在时强制覆盖。

Files#move()方法将文件从一个path移动到另一个path。同时可以设定目标的文件名,也就是说不仅可以实现移动功能,也可以实现重命名或移动+重命名。

  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. //moving file failed.
  8. e.printStackTrace();
  9. }

功能显而易见,StandardCopyOption.REPLACE_EXISTING参数的意义和copy方法中的一样。

Files#delete()方法可以删除一个文件或文件夹。

  1. Path path = Paths.get("data/subdir/logging-moved.properties");
  2. try {
  3. Files.delete(path);
  4. } catch (IOException e) {
  5. //deleting file failed
  6. e.printStackTrace();
  7. }

Files.walkFileTree()方法可以递归遍历目录树。它使用一个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. }

Files.walkFileTree()方法需要一个FileVisitor的实现类作为参数,实现FileVisitor接口就需要实现上述方法。如果不想做特殊实现或者只想实现一部分,可以继承SimpleFileVisitor类,它其中有对FileVisitor的方法的默认实现。

下面是示例:

  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. });

这些方法在遍历的不同时间被调用

  • preVisitDirectory()方法在访问任何目录前被调用。
  • postVisitDirectory()方法在访问任何目录后被调用。
  • visitFile()方法在访问任何文件时被调用。
  • visitFileFailed()在访问任何文件失败时被调用。(比如没权限)

每个方法返回;一个FileVisitResult枚举,这些返回指决定了遍历如何进行。包括

  • CONTINUE。表示遍历将继续正常进行。
  • TERMINATE。表示文件遍历将终止。
  • SKIP_SIBLINGS。表示文件遍历将继续,但不在访问此文件/目录的同级文件/目录。
  • SKIP_SUBTREE。表示文件遍历将继续,但不再访问此目录内的文件。

下面是一个通过walkFileTree()方法寻找名字为README.txt的文件的示例。注意这里的FileVisitor是继承SimpleFileVisitor的,不过重写了visitFile方法。

  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. }

下面是一个通过walkFileTree()方法删除名字为README.txt的文件的示例。注意这里的FileVisitor是继承SimpleFileVisitor的,不过重写了visitFile方法和postVisitDirectory方法。

Files#delete()方法仅在目录为空时删除目录,但下面的代码可以递归删除。

  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. }

Files类中还有许多其他方法,可以自己去看API。

版权声明:本文为WangXianSCU原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/WangXianSCU/p/15113215.html