拷贝目录树的时候,需要为文件和目录
递归调用 Files.copy() 方法。在开始编
写代码之前,要注意以下几点:
- 在拷贝目录中的文件之前,必须先拷贝目录本身。不管目录中是否有文件,拷贝目录后的结果都将是空目录。这个任务必须在 preVisitDirectory() 中完成。
- 拷贝文件最好在 visitFile() 方法中进行。
- 在拷贝文件或目录的过程中,你要考虑是否需要使用 REPLACE_EXISTING 和 COPY_ATTRIBUTES 配置项。
- 如果你需要保留目录的属性,那么要等到文件拷贝完成后在 postVisitDirectory() 方法中进行操作。
- 如果你选择了使用目标文件处理软链接(FOLLOW_LINKS),并且在目录树中有循环引用,那么将会触发 visitFileFailed() 方法并抛出 FileSystemLoopException 异常。
- 如果没有权限访问文件,那么visitFileFailed() 方法需要返回FileVisitResult.CONTINUE 或 TERMINATE,具体返回什么根据你的需求决定。
- 在拷贝过程中,可以用 FOLLOW_LINKS 选项来用目标文件处理软链接。
下面的代码将演示将 C:\rafaelnadal 子目录树拷贝到 C:\rafaelnadal_copy 中:
class="java" name="code">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/