`

commons-io之WildcardFileFilter的实现

阅读更多

 

       上次这个是最后一个FileFilter,没想到这个实现的还比较复杂,当时头脑比较晕,也没有看懂,就想这次专门的看一下源码,在看这个Filter之前,我们必须要理解FilenameUtils里面的wildMatch函数的实现,这个是最经典的通配符的匹配,可以好好看看。

 

       1. 首先我们应该来看一个小函数的实现splitOnTokens

   这个函数实际上还是比较简单的,它的主要意图就是要将字符串按*和?进行分割,这个实际上也比较简单,下面我们就来看一些它的具体实现。


   首先判断如果字符串里面不包含*或者?,则直接将字符串包装成String[]进行返回,这个比较好理解然后将字符串转char类型的array,进行遍历,如果发现字符是*或者?,则判断StringBuffer里面的字符长度是不是空,并将字符串加入的List里面,并把当前的buffer清空,如果是?则直接也将?加入到List里面,如果是*的情况就稍微复杂一些了。首先如果list是空,则直接将*加入到list里面,这种情景我们可以想象成第一个我们遇到了*,如果list不为空,我们就判断list的最后一个元素是不是*,如果这两个有一个满足,就把*加入到list里面,第二种情况我们也很好理解,主要是在通配符里面,如果是*的话是代表任意字符的,所以是不需要把两个连一块的*加入到list里面的。最后将list转化成String[]进行返回。


   这个函数里面有一个判断,i>0,真不知道这个是干什么的,我感觉只要list不为空就可以取元素了,这个可能还有等高人进行解释。

    static String[] splitOnTokens(String text) {
        // used by wildcardMatch
        // package level so a unit test may run on this

        if (text.indexOf("?") == -1 && text.indexOf("*") == -1) {
            return new String[] { text };
        }

        char[] array = text.toCharArray();
        ArrayList list = new ArrayList();
        StringBuffer buffer = new StringBuffer();
        for (int i = 0; i < array.length; i++) {
            if (array[i] == '?' || array[i] == '*') {
                if (buffer.length() != 0) {
                    list.add(buffer.toString());
                    buffer.setLength(0);
                }
                if (array[i] == '?') {
                    list.add("?");
                } else if (list.size() == 0 ||
                        (i > 0 && list.get(list.size() - 1).equals("*") == false)) {
                    list.add("*");
                }
            } else {
                buffer.append(array[i]);
            }
        }
        if (buffer.length() != 0) {
            list.add(buffer.toString());
        }

        return (String[]) list.toArray( new String[ list.size() ] );
    }
 

 

   2. wildcardMatch函数的理解

   这个函数特别不好理解,里面的变量命名wcs, textIdx,wcsIdx这样的很多,使得我们不能很好的把握作者的意图,这里我们可以看到一个好的命名是多么的重要。

 

 

public static boolean wildcardMatch(String filename, String wildcardMatcher, IOCase caseSensitivity) {
        // 在fileName和wildcardMatcher都为空的情况下,直接返回true,这样也比较符合情理
    	if (filename == null && wildcardMatcher == null) {
            return true;
        }
    	// 在filename和wildcardMatcher有一个为空的情况下,返回false,这个也比较好理解
        if (filename == null || wildcardMatcher == null) {
            return false;
        }
        // 如果caseSensitivity为空的情况下,我们默认为是sensitive
        if (caseSensitivity == null) {
            caseSensitivity = IOCase.SENSITIVE;
        }
        // 将filename转化为相应的形式,主要是case sensitive的时候全部转小写
        filename = caseSensitivity.convertCase(filename);
        // 将wildcase转化为相应的形式,主要是case sesnitive的时候全部转化成小写
        wildcardMatcher = caseSensitivity.convertCase(wildcardMatcher);
        // 这个函数我们再上面已经讲过了,主要是讲通配符进行分割,然后转化成String[]进行返回
        String[] wcs = splitOnTokens(wildcardMatcher);
        /*
         * 下面的这几个变量的意图我把握的不是很好,请大家在分析后进行补充,anyChars感觉是判断是不是
         * 匹配任意字符,textIdx用来指示现在匹配到那个字符了,wscIdx主要是来标明现在在使用那个通配
         * 符,也就是wcs的下标, backtrack是一个栈,用来处理复杂的*匹配,如果里面出现多个匹配上的,
         * 可能还需要进行回溯处理,这个地方也是这个函数最难理解的地方。
         */
        boolean anyChars = false;
        int textIdx = 0;
        int wcsIdx = 0;
        Stack backtrack = new Stack();

        // loop around a backtrack stack, to handle complex * matching
        do {
        	/*
        	 * 如果backtrack的长度大于0,说明有多个项已经匹配上了,所以要从栈里面进行恢复wcsIndex和
        	 * textIdx重新进行匹配
        	 */
            if (backtrack.size() > 0) {
                int[] array = (int[]) backtrack.pop();
                wcsIdx = array[0];
                textIdx = array[1];
                anyChars = true;
            }

            // loop whilst tokens and text left to process
            while (wcsIdx < wcs.length) {

            	// 如果是?,那么是匹配一个字符,所以当前的textIdx增加一个,anyChars当然是false了,这个很好理解
                if (wcs[wcsIdx].equals("?")) {
                    // ? so move to next text char
                    textIdx++;
                    anyChars = false;
                // 如果是*,这个anyChars当然是true了,还有就是如果是最后一个串的话,textIdx为字符串
                // 的长度,说明已经处理完了
                } else if (wcs[wcsIdx].equals("*")) {
                    // set any chars status
                    anyChars = true;
                    if (wcsIdx == wcs.length - 1) {
                        textIdx = filename.length();
                    }

                } else {
                    // matching text token
                    if (anyChars) {
                    	// 这个分支主要是来处理*的通配符的,首先在匹配串里面查找,并把下标给标示
                    	// 处理到那个字符的下标,如果没有找到,则表明没有匹配上,并进行返回
                        // any chars then try to locate text token
                        textIdx = filename.indexOf(wcs[wcsIdx], textIdx);
                        if (textIdx == -1) {
                            // token not found
                            break;
                        }
                        
                        // 再尝试查找字符串里面还有没有相应的字串出现了,如果有的话,将当前的匹配串和出现的下标
                        // 进行压栈,等待下一次的回溯处理。
                        int repeat = filename.indexOf(wcs[wcsIdx], textIdx + 1);
                        if (repeat >= 0) {
                            backtrack.push(new int[] {wcsIdx, repeat});
                        }
                    } else {
                    	// 如果不是匹配不上的话,直接break,这个也比较好理解
                        // matching from current position
                        if (!filename.startsWith(wcs[wcsIdx], textIdx)) {
                            // couldnt match token
                            break;
                        }
                    }

                    // matched text token, move text index to end of matched token
                    textIdx += wcs[wcsIdx].length();
                    anyChars = false;
                }

                wcsIdx++;
            }

            // full match
            if (wcsIdx == wcs.length && textIdx == filename.length()) {
                return true;
            }

        } while (backtrack.size() > 0);

        return false;
    }

    上面的我知道我可能理解的很不好,只能说是马马虎虎的看懂了代码,但对作者的意图等的完全不明白,看来自己的功力还真的很有限。 这里需要说明的是,我在理解这个代码的时候调试了很多次,也看了一下它的单元测试。其中我感觉两个稍微有意义的我摘取出来了,希望对大家理解代码有所帮助。

    FilenameUtils.wildcardMatch("New Bookmarks", "N?w ?o?k??r?s")

    FilenameUtils.wildcardMatch("Foo Bar Foo", "F*o Bar*")
    FilenameUtils.wildcardMatch("log.log", "*log")
 

  还有,这个类名叫: FilenameUtils, 方面名叫: wildcardMatch

  希望大家有时间了也分析一下,好好把这个再弄明白一些,也欢迎大家交流。

 

分享到:
评论

相关推荐

    commons-io-2.2-API文档-中文版.zip

    赠送jar包:commons-io-2.2.jar; 赠送原API文档:commons-io-2.2-javadoc.jar; 赠送源代码:commons-io-2.2-sources.jar; 包含翻译后的API文档:commons-io-2.2-javadoc-API文档-中文(简体)版.zip 对应Maven...

    commons-io-2.8.0-API文档-中英对照版.zip

    赠送jar包:commons-io-2.8.0.jar; 赠送原API文档:commons-io-2.8.0-javadoc.jar; 赠送源代码:commons-io-2.8.0-sources.jar; 赠送Maven依赖信息文件:commons-io-2.8.0.pom; 包含翻译后的API文档:commons-io...

    commons-io-2.11.0-API文档-中文版.zip

    赠送jar包:commons-io-2.11.0.jar; 赠送原API文档:commons-io-2.11.0-javadoc.jar; 赠送源代码:commons-io-2.11.0-sources.jar; 赠送Maven依赖信息文件:commons-io-2.11.0.pom; 包含翻译后的API文档:...

    commons-io-2.5-API文档-中文版.zip

    赠送jar包:commons-io-2.5.jar; 赠送原API文档:commons-io-2.5-javadoc.jar; 赠送源代码:commons-io-2.5-sources.jar; 赠送Maven依赖信息文件:commons-io-2.5.pom; 包含翻译后的API文档:commons-io-2.5-...

    commons-io-2.7-API文档-中文版.zip

    赠送jar包:commons-io-2.7.jar; 赠送原API文档:commons-io-2.7-javadoc.jar; 赠送源代码:commons-io-2.7-sources.jar; 赠送Maven依赖信息文件:commons-io-2.7.pom; 包含翻译后的API文档:commons-io-2.7-...

    commons-io-1.3.2-API文档-中文版.zip

    赠送jar包:commons-io-1.3.2.jar; 赠送原API文档:commons-io-1.3.2-javadoc.jar; 赠送源代码:commons-io-1.3.2-sources.jar; 赠送Maven依赖信息文件:commons-io-1.3.2.pom; 包含翻译后的API文档:commons-io...

    commons-io-2.7-API文档-中英对照版.zip

    赠送jar包:commons-io-2.7.jar 赠送原API文档:commons-io-2.7-javadoc.jar 赠送源代码:commons-io-2.7-sources.jar 包含翻译后的API文档:commons-io-2.7-javadoc-API文档-中文(简体)-英语-对照版.zip 对应...

    开发工具 commons-io-1.3.2

    开发工具 commons-io-1.3.2开发工具 commons-io-1.3.2开发工具 commons-io-1.3.2开发工具 commons-io-1.3.2开发工具 commons-io-1.3.2开发工具 commons-io-1.3.2开发工具 commons-io-1.3.2开发工具 commons-io-1.3.2...

    commons-fileupload-1.3.3.jar和commons-io-2.6.jar

    总的来说,`commons-fileupload-1.3.3.jar`和`commons-io-2.6.jar`是Java开发中不可或缺的工具,它们大大简化了文件上传的实现,同时也提供了良好的错误处理和资源管理机制,使得文件上传操作变得更加可靠和高效。...

    commons-io-2.4.jar包 官方免费版

    在压缩包中,除了`commons-io-2.4.jar`本身,还有其他URL文件,可能是提供额外资源的链接,如"去脚本之家看看.url"可能指向一个编程资源网站,"领取天猫淘宝内部优惠券.url"可能是促销信息,而"服务器软件.url"可能...

    commons-io-2.8.0-API文档-中文版.zip

    赠送jar包:commons-io-2.8.0.jar; 赠送原API文档:commons-io-2.8.0-javadoc.jar; 赠送源代码:commons-io-2.8.0-sources.jar; 赠送Maven依赖信息文件:commons-io-2.8.0.pom; 包含翻译后的API文档:commons-io...

    commons-io-2.0.1大全

    Commons IO是apache的一个开源的工具包,封装了IO操作的相关类,包含了最新的commons-io-2.0.1-bin,commons-io-2.0.1-src,commons-io-2.0.1-doc

    commons-io-2.4 包含了所有commons-io的jar包和源码

    在本案例中,我们讨论的是"commons-io-2.4"版本,这个版本包含了完整的Apache Commons IO库的jar包和源代码,适用于JDK 1.6及以上版本。 Apache Commons IO 提供了许多实用工具类,使得开发者在处理输入/输出操作时...

    commons-fileupload-1.2.1.jar 和commons-io-1.4.jar

    在实际开发中,当你需要在Web应用中实现文件上传功能时,首先会配置`commons-fileupload-1.2.1.jar`来解析请求,然后利用`commons-io-1.4.jar`处理上传后的文件,比如保存到服务器的指定目录,或者进行一些预处理...

    java-IO流 commons-io-2.11.0.jar

    java-IO流 commons-io-2.11.0.jar

    commons-io-2.11.0-API文档-中英对照版.zip

    赠送jar包:commons-io-2.11.0.jar; 赠送原API文档:commons-io-2.11.0-javadoc.jar; 赠送源代码:commons-io-2.11.0-sources.jar; 赠送Maven依赖信息文件:commons-io-2.11.0.pom; 包含翻译后的API文档:...

    commons-io-2.11.0-bin.zip

    在标题中提到的"commons-io-2.11.0-bin.zip"是Apache Commons IO库的一个二进制发行版,版本号为2.11.0。这个压缩包包含了该库的所有编译后的类文件和必要的资源,使得开发者能够在他们的项目中方便地使用Apache ...

    commons-io-2.5.jar

    commons-io-2.5 &lt;groupId&gt;org.apache.commons &lt;artifactId&gt;commons-parent &lt;version&gt;39 &lt;modelVersion&gt;4.0.0 &lt;groupId&gt;commons-io &lt;artifactId&gt;commons-io &lt;version&gt;2.5 &lt;name&gt;Apache Commons IO&lt;/name&gt;

    commons-fileupload.jar和commons-io.jar

    然后在Controller中,可以直接通过`@RequestParam("file") MultipartFile file`来接收上传的文件,这里MultipartFile就是由`commons-fileupload`和`commons-io`支持的。 对于MyBatis,虽然它主要关注数据库操作,但...

    commons-io-2.11.0.rar

    "commons-io-2.11.0.rar"是Apache Commons IO库的版本2.11.0的压缩包文件,包含了该版本的所有源代码、类库和相关的文档。 Apache Commons IO库的核心特性包括: 1. 文件操作:提供了一系列静态方法来操作文件,如...

Global site tag (gtag.js) - Google Analytics