簡體   English   中英

使用Java NIO.2 FileVisitor和Files.walkFileTree(…)遞歸移動非空目錄

[英]Moving not empty directory recursively using Java NIO.2 FileVisitor and Files.walkFileTree(…)

我看到了很多有關如何使用Java NIO.2遞歸地復制或刪除文件的示例。 例如,這是復制文件夾及其所有內容的方法:

/**
 * Copies a folder with all contents recursively. Class implements
 * {@code FileVisitor} interface.
 * @author Ernestas Gruodis
 */
public static class TreeCopy implements FileVisitor<Path> {

        private final Path source;
        private final Path target;
        private final boolean replace;
        private final CopyOption[] options;
        private final ArrayList<Object[]> events = new ArrayList<>();

        /**
         * Copies a folder with all contents recursively.
         *
         * @param source source file path.
         * @param target target file path.
         * @param replace {@code true} if existing file should be replaced.
         */
        public TreeCopy(Path source, Path target, boolean replace) {
            this.source = source;
            this.target = target;
            this.replace = replace;

            options = replace ? new CopyOption[]{COPY_ATTRIBUTES, REPLACE_EXISTING} : new CopyOption[0];
        }

        @Override
        public synchronized FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {

            Path newDir = target.resolve(source.relativize(dir));
            try {
                Files.copy(dir, newDir, options);
            } catch (FileAlreadyExistsException ex) {
                if (!replace) {
                    events.add(new Object[]{"Folder already exists", newDir, ex});
                    return FileVisitResult.TERMINATE;
                } else {
                    return FileVisitResult.CONTINUE;
                }
            } catch (DirectoryNotEmptyException ex) {
                //Ignore
            } catch (IOException ex) {
                events.add(new Object[]{"Unable to create a folder", newDir, ex});
                return FileVisitResult.SKIP_SUBTREE;
            }
            return FileVisitResult.CONTINUE;
        }

        @Override
        public synchronized FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {

            Path newFile = target.resolve(source.relativize(file));
            try {
                Files.copy(file, newFile, options);
            } catch (FileAlreadyExistsException ex) {
                events.add(new Object[]{"File already exists", newFile, ex});
            } catch (NoSuchFileException ex) {
                events.add(new Object[]{"No such file", newFile.getParent(), ex});
            } catch (IOException ex) {
                events.add(new Object[]{"Unable to create a file", newFile, ex});
            }
            return FileVisitResult.CONTINUE;
        }

        @Override
        public synchronized FileVisitResult postVisitDirectory(Path dir, IOException exc) {

            if (exc == null) {
                Path newDir = target.resolve(source.relativize(dir));
                try {
                    FileTime time = Files.getLastModifiedTime(dir);
                    Files.setLastModifiedTime(newDir, time);
                } catch (IOException ex) {
                    events.add(new Object[]{"Unable to copy all attributes to", newDir, ex});
                }
            }
            return FileVisitResult.CONTINUE;
        }

        @Override
        public synchronized FileVisitResult visitFileFailed(Path file, IOException ex) {

            if (ex instanceof FileSystemLoopException) {
                events.add(new Object[]{"Cycle detected", file, ex});
            } else {
                events.add(new Object[]{"Unable to copy", file, ex});
            }
            return FileVisitResult.CONTINUE;
        }

        /**
         * Returns errors which happened while copying a directory.
         *
         * @return {@code ArrayList<Object[]>} error list, where at each entry
         * of {@code Object[]} index:
         * <ul><li> 0 - {@code String} - error description;
         * </li><li> 1 - {@code Path} - target folder/file path;
         * </li><li> 2 - {@code Exception} - specific exception.
         * </li></ul>
         */
        public ArrayList<Object[]> getEvents() {

            return events;
        }
    }


Path source = Paths.get("/toCopyDir"),
    target = Paths.get("/someDir2/etc/toCopyDir");

EnumSet<FileVisitOption> opts = EnumSet.of(FileVisitOption.FOLLOW_LINKS);
TreeCopy tc = new TreeCopy(source, target, true);
try {
   Files.walkFileTree(source, opts, Integer.MAX_VALUE, tc);
} catch (IOException ex) {
   //Handle exception
}

但是如何移動包含文件的文件夾? 有一個方法Files.move(Path source, Path target, CopyOption... options) throws IOException 誰能給出一個真正有效的例子?

我認為解決方案可能是在preVisitDirectory(...) Files.copy(...)中使用preVisitDirectory(...) ,然后在Files.delete(...)中使用postVisitDirectory(...) ,類似。

這是一個解決方案:

def moveDir(path: Path, to: Path): Unit = {
Files.createDirectories(to)
Files.walkFileTree(
  path,
  new SimpleFileVisitor[Path] {
    override def preVisitDirectory(
        dir: Path,
        attrs: BasicFileAttributes): FileVisitResult = {
      val targetDir = to.resolve(path.relativize(dir))
      try Files.createDirectory(targetDir)
      catch {
        case e: FileAlreadyExistsException =>
          if (!Files.isDirectory(targetDir)) throw e
      }
      FileVisitResult.CONTINUE
    }

    override def visitFile(file: Path,
                           attrs: BasicFileAttributes): FileVisitResult = {
      Files.move(file, to.resolve(path.relativize(file)))
      FileVisitResult.CONTINUE
    }
  }
)

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM