- 在拷贝目录中的文件之前,必须先拷贝目录本身。不管目录中是否有文件,拷贝目录后的结果都将是空目录。这个任务必须在 preVisitDirectory() 中完成。
- 拷贝文件最好在 visitFile() 方法中进行。
- 在拷贝文件或目录的过程中,你要考虑是否需要使用 REPLACE_EXISTING 和 COPY_ATTRIBUTES 配置项。
- 如果你需要保留目录的属性,那么要等到文件拷贝完成后在 postVisitDirectory() 方法中进行操作。
- 如果你选择了使用目标文件处理软链接(FOLLOW_LINKS),并且在目录树中有循环引用,那么将会触发 visitFileFailed() 方法并抛出 FileSystemLoopException 异常。
- 如果没有权限访问文件,那么visitFileFailed() 方法需要返回FileVisitResult.CONTINUE 或 TERMINATE,具体返回什么根据你的需求决定。
- 在拷贝过程中,可以用 FOLLOW_LINKS 选项来用目标文件处理软链接。
下面的代码将演示将 C:\rafaelnadal 子目录树拷贝到 C:\rafaelnadal_copy 中:
import java.nio.file.FileSystemLoopException; import java.nio.file.attribute.FileTime; import java.io.IOException; import java.nio.file.FileVisitOption; import java.nio.file.FileVisitResult; import java.nio.file.FileVisitor; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.attribute.BasicFileAttributes; import java.util.EnumSet; import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; import static java.nio.file.StandardCopyOption.COPY_ATTRIBUTES; class CopyTree implements FileVisitor { private final Path copyFrom; private final Path copyTo; public CopyTree(Path copyFrom, Path copyTo) { this.copyFrom = copyFrom; this.copyTo = copyTo; } static void copySubTree(Path copyFrom, Path copyTo) throws IOException { try { Files.copy(copyFrom, copyTo, REPLACE_EXISTING, COPY_ATTRIBUTES); } catch (IOException e) { System.err.println("Unable to copy " + copyFrom + " [" + e + "]"); } } @Override public FileVisitResult postVisitDirectory(Object dir, IOException exc) throws IOException { if (exc == null) { Path newdir = copyTo.resolve(copyFrom.relativize((Path) dir)); try { FileTime time = Files.getLastModifiedTime((Path) dir); Files.setLastModifiedTime(newdir, time); } catch (IOException e) { System.err.println("Unable to copy all attributes to: " + newdir+" ["+e+ "]"); } } else { throw exc; } return FileVisitResult.CONTINUE; } @Override public FileVisitResult preVisitDirectory(Object dir, BasicFileAttributes attrs) System.out.println("Copy directory: " + (Path) dir); Path newdir = copyTo.resolve(copyFrom.relativize((Path) dir)); try { Files.copy((Path) dir, newdir, REPLACE_EXISTING, COPY_ATTRIBUTES); } catch (IOException e) { System.err.println("Unable to create " + newdir + " [" + e + "]"); return FileVisitResult.SKIP_SUBTREE; } return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFile(Object file, BasicFileAttributes attrs) throws IOException { System.out.println("Copy file: " + (Path) file); copySubTree((Path) file, copyTo.resolve(copyFrom.relativize((Path) file))); return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFileFailed(Object file, IOException exc) throws IOException { if (exc instanceof FileSystemLoopException) { System.err.println("Cycle was detected: " + (Path) file); } else { System.err.println("Error occurred, unable to copy:" +(Path) file+" ["+ exc + "]"); } return FileVisitResult.CONTINUE; } } class Main { public static void main(String[] args) throws IOException { Path copyFrom = Paths.get("C:/rafaelnadal"); Path copyTo = Paths.get("C:/rafaelnadal_copy"); CopyTree walk = new CopyTree(copyFrom, copyTo); EnumSet opts = EnumSet.of(FileVisitOption.FOLLOW_LINKS); Files.walkFileTree(copyFrom, opts, Integer.MAX_VALUE, walk); } }
运行了上面的代码后,你将发现 C:\rafaelnadal_copy 和 C:\rafaelnadal 将会有完全一样的目录树和属性。
文章来源: http://www.aptusource.org/2014/04/nio-2-writing-a-copy-files-application/