java nio: walkFileTree实现文件夹复制移动删除

从java 1.7开始,java提供了java.noi.file.Files类用于更方便的实现文件/文件夹操作。 在Files中提供了丰富的静态方法用于文件操作,Files也提供了文件移动和复制操作(Files.move,Files.copy),但是对于不为的空文件夹,不能调用Files.move,Files.copy实现文件夹下所有文件的复制和移动。 根据Files.move,Files.copy的说明,如果要移动/复制包含子目录的文件夹,需要用Files.walkFileTree方法配合Files.move,Files.copy来实现。以下是实现代码:

NioFileUtil.java

package net.gdface.iadb;

import java.io.IOException;
import java.nio.file.CopyOption;
import java.nio.file.DirectoryNotEmptyException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.StandardCopyOption;
import java.nio.file.attribute.BasicFileAttributes;

/**
 * 使用于NIO实现文件夹的复制/移动,删除<br>
 * 需要java 1.7以上版本支持
 * @author guyadong
 *
 */
public class NioFileUtil {
    /**
     * 复制文件夹
     * @param source
     * @param target
     * @param options
     * @throws IOException
     * @see {@link #operateDir(boolean, Path, Path, CopyOption...)}
     */
    public static void copyDir(Path source, Path target, CopyOption... options) throws IOException{
        operateDir(false, source, target, options);
    }
    /**
     * 移动文件夹
     * @param source
     * @param target
     * @param options
     * @throws IOException
     * @see {@link #operateDir(boolean, Path, Path, CopyOption...)}
     */
    public static void moveDir(Path source, Path target, CopyOption... options) throws IOException{
        operateDir(true, source, target, options);
    }
    /**
     * 复制/移动文件夹
     * @param move 操作标记,为true时移动文件夹,否则为复制
     * @param source 要复制/移动的源文件夹
     * @param target 源文件夹要复制/移动到的目标文件夹
     * @param options 文件复制选项 
     * @throws IOException
     * @see Files#move(Path, Path, CopyOption...)
     * @see Files#copy(Path, Path, CopyOption...)
     * @see Files#walkFileTree(Path, java.nio.file.FileVisitor)
     */
    public static void operateDir(boolean move,Path source, Path target, CopyOption... options) throws IOException{
        if(null==source||!Files.isDirectory(source))
            throw new IllegalArgumentException("source must be directory");
        Path dest = target.resolve(source.getFileName());
        // 如果相同则返回
        if(Files.exists(dest)&&Files.isSameFile(source, dest))return;
        // 目标文件夹不能是源文件夹的子文件夹
        // isSub方法实现参见另一篇博客 http://blog.csdn.net/10km/article/details/54425614
        if(isSub(source,dest))
            throw new IllegalArgumentException("dest must not  be sub directory of source");
        boolean clear=true;     
        for(CopyOption option:options)
            if(StandardCopyOption.REPLACE_EXISTING==option){
                clear=false;
                break;
            }
        // 如果指定了REPLACE_EXISTING选项则不清除目标文件夹
        if(clear)
            deleteIfExists(dest);
        Files.walkFileTree(source, 
                new SimpleFileVisitor<Path>() {

                    @Override
                    public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
                        // 在目标文件夹中创建dir对应的子文件夹
                        Path subDir = 0==dir.compareTo(source)?dest:dest.resolve(dir.subpath(source.getNameCount(), dir.getNameCount()));
                        Files.createDirectories(subDir);
                        return FileVisitResult.CONTINUE;
                    }

                    @Override
                    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                        if(move)
                            Files.move(file, dest.resolve(file.subpath(source.getNameCount(), file.getNameCount())),options);
                        else
                            Files.copy(file, dest.resolve(file.subpath(source.getNameCount(), file.getNameCount())),options);
                        return FileVisitResult.CONTINUE;
                    }

                    @Override
                    public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
                        // 移动操作时删除源文件夹
                        if(move)
                            Files.delete(dir);
                        return super.postVisitDirectory(dir, exc);
                    }
                });
    }

    /**
     * 强制删除文件/文件夹(含不为空的文件夹)<br>
     * @param dir
     * @throws IOException
     * @see Files#deleteIfExists(Path)
     * @see Files#walkFileTree(Path, java.nio.file.FileVisitor)
     */
    public static void deleteIfExists(Path dir) throws IOException {
        try {
            Files.deleteIfExists(dir);
        } catch (DirectoryNotEmptyException e) {
            Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {
                @Override
                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                    Files.delete(file);
                    return FileVisitResult.CONTINUE;
                }

                @Override
                public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
                    Files.delete(dir);
                    return super.postVisitDirectory(dir, exc);
                }
            });
        }
    }

}

测试代码

    public void testCopy() throws IOException{
        Path start = Paths.get("d:\\tmp\\storeroot\\origin");
        Path target = Paths.get("E:\\tmp\\storeroot");
        NioFileUtil.copyDir(start, target);
    }

关于Files.walkFileTree方法的使用说明,参见这篇博客《walkFileTree、FileVisitor(遍历文件/目录)》,说得很详细了

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Hongten

彩色照片转换为黑白照片(Color image converted to black and white picture)

This blog will be talking about the color image converted to black and white pic...

13520
来自专栏菩提树下的杨过

base64编码在silverlight中的使用

在传统的.net应用中,使用base64编码字符串是一件很轻松的事情,比如下面这段代码演示了如何将本地文件转化为base64字符串,并且将base64字符串又还...

23570
来自专栏拂晓风起

jQuery 和 json 简单例子(注意callback函数的处理!!) (servlet返回json,jquery更新,java json)

13630
来自专栏c#开发者

Modal popup dialog window with multiple parameters

Introduction This article shows a modal popup dialog window which passes and ret...

33750
来自专栏流媒体人生

ATL源码学习3---接口的查询支持

b. _InternalQueryInterface函数调用InternalQueryInterface函数,定义在BEGIN_COM_MAP宏内部

9630
来自专栏函数式编程语言及工具

Akka(8): 分布式运算:Remoting-远程查找式

  Akka是一种消息驱动运算模式,它实现跨JVM程序运算的方式是通过能跨JVM的消息系统来调动分布在不同JVM上ActorSystem中的Actor进行运算,...

45990
来自专栏Hongten

java画图程序_图片用字母画出来_源码发布

主要是把一些调试的截图发布出来,现在程序调试我认为可以了(当然,你如果还想调试的话,也可以下载源码自己调试)。

13930
来自专栏Java 技术分享

Ajax 案例之三级联动

37960
来自专栏码匠的流水账

spring security filter获取请求的urlpattern

本文主要讲一下如何在spring security filter里头获取请求的HandlerMapping.BEST_MATCHING_PATTERN_ATTR...

11710
来自专栏技术之路

wpf键盘记录器

很简单的一个wpf键盘记录器 ? 这个程序我一样用了全局勾子,之前用的都是winform上运行了,前一段时间 在国外的论坛上逛看到了一个wpf能用的就做了一个小...

23750

扫码关注云+社区

领取腾讯云代金券