[NIO.2] 第三十六篇 编写一个文件拷贝应用

阅读更多
拷贝目录树的时候,需要为文件和目录递归调用 Files.copy() 方法。在开始编写代码之前,要注意以下几点:

  • 在拷贝目录中的文件之前,必须先拷贝目录本身。不管目录中是否有文件,拷贝目录后的结果都将是空目录。这个任务必须在 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/

你可能感兴趣的:(java,NIO.2)