“访问者模式”--如何实现删除多级目录

1,编码实现

注:该方法为OnJava8 File章节提供的方法,基于 nio包下的 Files.walkFileTree方法实现。

经过查看后发现,该方法(Files.walkFileTree)在jre1.7中也已经存在,所以Java7也支持使用。 


import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.io.IOException;

public class RmDir {

    /**
     * 删除多级目录下的文件
     * @param dir
     * @throws IOException
     */
    public static void rmdir(Path dir) throws IOException {
        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 FileVisitResult.CONTINUE;
            }
        });
    }

    /**
     * 测试
     * @param args
     */
    public static void main(String[] args) {
        // 获取测试目录
        Path path = Paths.get("E:", "demo");
        System.err.println(path.getFileName());
        try {
            rmdir(path);
            // Files.delete(path);
        } catch (Exception e) {
            System.err.println(e.getMessage());
        }
    }

}

2,原理解析

Files.walkFileTree 方法的实现原理为访问者模式,访问者模式包含以下这几个对象,
 

● Visitor——抽象访问者
抽象类或者接口,声明访问者可以访问哪些元素,具体到程序中就是visit方法的参数定
义哪些对象是可以被访问的。


● ConcreteVisitor——具体访问者
它影响访问者访问到一个类后该怎么干,要做什么事情。


● Element——抽象元素
接口或者抽象类,声明接受哪一类访问者访问,程序上是通过accept方法中的参数来定
义的。


● ConcreteElement——具体元素
实现accept方法,通常是visitor.visit(this),基本上都形成了一种模式了。


● ObjectStruture——结构对象
元素产生者,一般容纳在多个不同类、不同接口的容器,如List、Set、Map等,在项目
中,一般很少抽象出这个角色。

解析一:具体访问者

Files.walkFileTree方法的第二个参数是实现一个具体访问者(ConcreteVisitor),它所实现的类如 SimpleFileVisitor 是一个具体的访问者对象。内部提供了包括访问文件,目录已经在访问之前触发等一系列的方法,可以到具体的源码中看其注释。

解析二:具体元素

访问者中的方法被那个类型对象访问是由具体元素决定的,该方法中其实是Path作为具体元素(ConcreteElement),但是确是由Files类来实现目录和文件所调用的访问者的方法,Files类作为一个代理来解除了Path类和访问者之间的耦合(此处属于个人见解,如不符实,请评论告知进行修改),打开Files方法中实现的walkFileTree方法,发现它实现了类型的判断和具体方法的访问

public static Path walkFileTree(Path start,
                                    Set<FileVisitOption> options,
                                    int maxDepth,
                                    FileVisitor<? super Path> visitor)
        throws IOException
    {
        /**
         * Create a FileTreeWalker to walk the file tree, invoking the visitor
         * for each event.
         */
        try (FileTreeWalker walker = new FileTreeWalker(options, maxDepth)) {
            FileTreeWalker.Event ev = walker.walk(start);
            do {
                FileVisitResult result;
                switch (ev.type()) {
                    case ENTRY :
                        IOException ioe = ev.ioeException();
                        if (ioe == null) {
                            assert ev.attributes() != null;
                            result = visitor.visitFile(ev.file(), ev.attributes());
                        } else {
                            result = visitor.visitFileFailed(ev.file(), ioe);
                        }
                        break;

                    case START_DIRECTORY :
                        result = visitor.preVisitDirectory(ev.file(), ev.attributes());

                        // if SKIP_SIBLINGS and SKIP_SUBTREE is returned then
                        // there shouldn't be any more events for the current
                        // directory.
                        if (result == FileVisitResult.SKIP_SUBTREE ||
                            result == FileVisitResult.SKIP_SIBLINGS)
                            walker.pop();
                        break;

                    case END_DIRECTORY :
                        result = visitor.postVisitDirectory(ev.file(), ev.ioeException());

                        // SKIP_SIBLINGS is a no-op for postVisitDirectory
                        if (result == FileVisitResult.SKIP_SIBLINGS)
                            result = FileVisitResult.CONTINUE;
                        break;

                    default :
                        throw new AssertionError("Should not get here");
                }

                if (Objects.requireNonNull(result) != FileVisitResult.CONTINUE) {
                    if (result == FileVisitResult.TERMINATE) {
                        break;
                    } else if (result == FileVisitResult.SKIP_SIBLINGS) {
                        walker.skipRemainingSiblings();
                    }
                }
                ev = walker.next();
            } while (ev != null);
        }

        return start;
    }

附:以上纯属个人见解,如有错误,敬请指示

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值