博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
杂篇-从整理文件发起的杂谈[-File-]
阅读量:6569 次
发布时间:2019-06-24

本文共 27300 字,大约阅读时间需要 91 分钟。

有些东西很简单,简单到你不想去想,比如:为什么天是蓝的?--局限物语

零、前言

说一下本篇的初衷: coder盘作为工作盘有点乱,想整理一下

也想寻求一个方便管理工程的点子,既然File类玩的滚瓜烂熟,何妨玩一下
加之File的天然递归性,再熟悉一下递归也不错,所以便有此篇,
本文前奏有点长,好戏在后面----注意:本文的重点不是操作,而是思想


一、创建Filer类

java的File对象只是提供一些基本信息,这也是情理之中

感觉可以封装一下,提供更多的信息,比如下面的,文件夹大小,子文件个数等


1.先举一个简单的例子:目录结构如下:
|---edite    |---top    |---toly        |---界面编程GUI            |---Edit.java            |---FileHelper.java            |---IOUtils.java    |---edit.jar    |---main.txt复制代码

2.Filer信息封装

先实现子文件夹、文件的个数、文件夹大小三个属性

public class Filer {    private String name;//文件夹名    private int dirCount;//子文件夹数量---不包括自身    private int fileCount;//文件的个数    private long length; //文件夹大小        public File getFile() {        return file;    }    public int getDirCount() {        return dirCount - 1;    }    public int getFileCount() {        return fileCount;    }    public long getLength() {        return length;    }}复制代码

3.定义文件节点类

考虑到一个文件夹下或有多个文件,这里用ArrayList装一下,

考虑到默认情况下ArrayList的初始数组为10个,这里取4个(很可能一个文件夹里就一两个文件)

/** * 文件节点 */private class FileNode {    public ArrayList
child;//子节点集合 public File file; //文件路径 public FileNode(File file) { this.file = file; child = new ArrayList<>(4); }}复制代码

4.Filer的初始化
private FileNode root;//根节点 public Filer(String rootPath) {     file = new File(rootPath);     root = new FileNode(file);//初始化根节点 }复制代码

5.文件的扫描

你可以结合下面的分析,自己debug走一走

public Filer(String rootPath) {    file = new File(rootPath);    root = new FileNode(file);    scan(root);//扫描根目录}private void scan(FileNode node) {    File file = node.file;    if (file.isFile()) {//如果节点是文件        return;    }    File[] files = file.listFiles();    for (File f : files) {        FileNode child = new FileNode(f);        node.child.add(child);        if (f.isDirectory()) {            scan(child);        }    }}复制代码

第一次调用scan时,如果是文件夹,就遍历文件夹, 里面不管是文件还是文件夹都加到child里

当遇到文件夹是便会触发scan来扫描该文件夹,这便是最简单的递归

无返回值,只是触发行为(实际每次触发scan方法调用完成,会有方法出栈的步骤)

就这样一个树形的结构就形成了


6.既然一个一个节点连接了这颗树

那么完全可以在扫描的时候多做一些事,比如维护那三个成员变量

private void scan(FileNode node) {    File file = node.file;    if (file.isFile()) {//如果节点是文件        return;    }    File[] files = file.listFiles();    for (File f : files) {        FileNode child = new FileNode(f);        node.child.add(child);        if (f.isDirectory()) {            dirCount++;//每调用一次说明有一个文件夹            scan(child);        } else {            fileCount++;//每调用一次说明有一个文件            length += f.length();//维护length        }    }}复制代码

7.调用

public class MakeDirInfo {    public static void main(String[] args) {        File root = new File("J:\\edite");        Filer filer = new Filer(root.getAbsolutePath());                long length = filer.getLength();//17.86621KB        System.out.println(Formater.format_B_KB_MB_GB(length));//5        long modifyTime = filer.getFile().lastModified();//2018-10-06 15:19:39        System.out.println(Formater.format_yyyy_MM_dd_kk_mm_ss(modifyTime));//5        System.out.println(filer.getFile().getName());//edite        System.out.println(+filer.getDirCount()+"个文件夹");//3        System.out.println(filer.getFileCount()+"个文夹");//5        System.out.println(filer.getFileFilter().get(0).count);//5    }}复制代码

用一个大一些的文件夹看一下:感觉7秒多挺慢的,电脑自身的查看器反应完要9秒,所以还好吧


二、全副武装

1.统计文件夹中文件类型

想一下,花了7秒得到三个属性,而且把文件都遍历一边了,感觉有点亏

现在想看一下有多少种文件,这要求不过分吧,想想也简单,看一下后缀名就行了

public Filer(String rootPath) {    mSet = new HashSet<>();    ...}private void scan(FileNode node) {    File file = node.file;    if (file.isFile()) {//如果节点是文件        return;    }    File[] files = file.listFiles();    for (File f : files) {        FileNode child = new FileNode(f);        node.child.add(child);        if (f.isDirectory()) {            dirCount++;//每调用一次说明有一个文件夹            scan(child);        } else {            fileCount++;//每调用一次说明有一个文件            String fileName = f.getName();            String suffix = fileName.substring(fileName.lastIndexOf(".") + 1);            mSet.add(suffix);            length += f.length();        }    }}复制代码

2.策略的出现

这有个问题,也许最近设计模式想多了,六大原则时刻在心

Filer在已经很好的完成了它的扫描工作,这里让Filer多一个成员变量mSet
感觉不爽,else里的三句代码看着也不优雅,如果需要改动,还有找在哪里,
代码如果多起来,茫茫码海,哪去找这三行!何不提取策略呢?

/** * 作者:张风捷特烈 * 时间:2019/2/13/013:13:44 * 邮箱:1981462002@qq.com * 说明:后缀名过滤器 */public class SuffixFilter {    private Set
suffixs; public Set
getSuffixs() { return suffixs; } public SuffixFilter() { suffixs = new HashSet<>(); } public void filter(File file) { String fileName = file.getName(); String suffix = fileName.substring(fileName.lastIndexOf(".") + 1); suffixs.add(suffix); }}---->[Filer]-------------private SuffixFilter mFilter;public Filer(SuffixFilter filter) { mFilter = filter;}public void setFilter(SuffixFilter filter) { mFilter = filter;}public void scan() { scan(root);}public void scan() {...else { fileCount++;//每调用一次说明有一个文件 if (mFilter != null) { mFilter.filter(f); } length += f.length();}---->[使用]-------------Filer filer = new Filer("J:\\edite");SuffixFilter filter = new SuffixFilter();filer.setFilter(filter);//设置过滤器filer.scan();Set
suffixs = filter.getSuffixs();for (String suffix : suffixs) { System.out.print(suffix+"、");}复制代码


3.当需要修改时,分离的优势显现

这样就是得Filer类和获取文件类型这个动作解耦,Filter只需要关注扫描任务

比如有些文件名没有后缀名,这样时就要修改策略,总不能都算一种文件吧?
有专门负责的类,只需去修改SuffixFilter的过滤方法就行了,比在Filer里好些

/** * 作者:张风捷特烈 * 时间:2019/2/13/013:13:44 * 邮箱:1981462002@qq.com * 说明:后缀名过滤器 */public class SuffixFilter {    private Set
suffixs; public Set
getSuffixs() { return suffixs; } public SuffixFilter() { suffixs = new HashSet<>(); } public void filter(File file) { String fileName = file.getName(); String suffix = fileName.substring(fileName.lastIndexOf(".") + 1); if (suffix.length() < 10) {//如果长度大于10,是other suffixs.add(suffix); }else { suffixs.add("other"); } }}复制代码


4.抽象与拓展

既然是策略,就可以有多种,所以抽象出共性,自定义个性来拓展

很明显,有一个公共的抽象方法,filter(File),既然是过滤,应该有过滤条件

/** * 作者:张风捷特烈 * 时间:2019/2/13/013:14:31 * 邮箱:1981462002@qq.com * 说明:文件过滤接口 */public interface FileFilter {    /**     * 根据路径判断是否过滤出     * @param file 文件     * @return 是否可以执行filter     */    boolean iCanGo(File file);    /**     * 过滤的逻辑操作     * @param file 文件     */    void filter(File file);}/** * 作者:张风捷特烈 * 时间:2019/2/13/013:13:44 * 邮箱:1981462002@qq.com * 说明:后缀名过滤器 */public class SuffixFilter implements FileFilter{    private Set
suffixs; public Set
getSuffixs() { return suffixs; } public SuffixFilter() { suffixs = new HashSet<>(); } @Override public boolean iCanGo(File file) { return file.isFile(); } public void filter(File file) { String fileName = file.getName(); String suffix = fileName.substring(fileName.lastIndexOf(".") + 1); if (suffix.length() < 10) {//如果长度大于10,是other suffixs.add(suffix); }else { suffixs.add("other"); } }}---->[Filer]----------private FileFilter mFilter;public Filer(FileFilter filter) { mFilter = filter;}public void setFilter(FileFilter filter) { mFilter = filter;}public void scan() { ... for (File f : files) { FileNode child = new FileNode(f); child.deep = curDeep; node.child.add(child); if (mFilter != null && mFilter.iCanGo(f)) { mFilter.filter(f); } ... }复制代码

5.基于接口的功能拓展

好好的为什么要加个接口,是我初学java时的一个大疑问,导致我设计模式稀里糊涂

现在要添加一个获取一个文件夹下的所有java文件的功能,有了接口就非常方便了

/** * 作者:张风捷特烈 * 时间:2019/2/13/013:10:59 * 邮箱:1981462002@qq.com * 说明:获取一个文件夹下所有java文件路径 */public class JavaFilter implements FileFilter {    private ArrayList
javaFiles; public ArrayList
getJavaFiles() { return javaFiles; } public JavaFilter() { javaFiles = new ArrayList<>(); } @Override public boolean iCanGo(File file) { String path = file.getAbsolutePath(); String suffix = path.substring(path.lastIndexOf(".") + 1); return suffix.equals("java"); } @Override public void filter(File file) { javaFiles.add(file.getAbsolutePath()); }}---->[使用]----------Filer filer = new Filer("J:\\Github");JavaFilter javaFilter = new JavaFilter();filer.setFilter(javaFilter);filer.scan();for (String s : javaFilter.getJavaFiles()) { System.out.println(s);}复制代码

可见过滤操作已经和Filer分离了,拓展了一个查看所有java文件的功能

没有修改Filer里的任何代码,对于Filer来说就是优秀的
iCanGo方法用来控制筛选,filter用来操作...一个控制系法师,一个输出系战士,吊打无误

当然你也可以将类型变成参数,通过构造来,这样会更方便

/** * 作者:张风捷特烈 * 时间:2019/2/13/013:10:59 * 邮箱:1981462002@qq.com * 说明:获取一个文件夹下所有某类型文件的路径 */public class TypeFilter implements FileFilter {    private ArrayList
javaFiles; private String type; public TypeFilter(String type) { this.type = type; javaFiles = new ArrayList<>(); } public ArrayList
getJavaFiles() { return javaFiles; } @Override public boolean iCanGo(File file) { String path = file.getAbsolutePath(); String suffix = path.substring(path.lastIndexOf(".") + 1); return suffix.equals(type); } @Override public void filter(File file) { javaFiles.add(file.getAbsolutePath()); }}复制代码

6.批量修改操作

有很多时候感觉很像接力赛,一旦将棒子交给下一个人,你就不用跑了

Filer就是这样,我把遍历到的File交给你Filter,你爱怎搞自己搞,跟我无关
有点像服务器发数据,数据给你了我就没事了,你怎么处理你自己看着办
现在我想要将一个文件夹下的所有java文件结尾加一行字的需求:
怎么操作我说了算,甚至不用新建类,写个匿名内部类就行了,拿到文件,就写呗!

Filer filer = new Filer("J:\\edite");filer.setFilter(new FileFilter() {    @Override    public boolean iCanGo(String path) {        String path = file.getAbsolutePath();        String suffix = path.substring(path.lastIndexOf(".") + 1);        return suffix.equals("java");    }    @Override    public void filter(File file) {        try {            FileWriter fw = new FileWriter(file, true);            String time = Formater.format_yyyy_MM_dd_kk_mm_ss(System.currentTimeMillis());            fw.write("// 张风捷特烈 修改:" + time);            fw.close();        } catch (IOException e) {            e.printStackTrace();        }    }});filer.scan();复制代码

这样来看,批量改名字还不是手到擒来


7.多个过滤器

反正遍历都遍历了,不用白不用,多几个过滤器,多几重操作

//过滤器集合private ArrayList
mFilters = new ArrayList<>();public void addFilter(FileFilter countFilter) { mFilters.add(countFilter);}public void scan() { ... for (FileFilter filter : mFilters) { if (filter != null && filter.iCanGo(f)) { filter.filter(f); } } ... ---->[使用]-----Filer filer = new Filer("J:\\edite");JavaEditer javaEditer = new JavaEditer();TypeFilter typeFilter = new TypeFilter("java");filer.addFilter(javaEditer);filer.addFilter(typeFilter);filer.scan();for (String s : typeFilter.getFiles()) { System.out.println(s);}复制代码

三、言归正传

1.添加节点深度字段并维护

每当文件夹时curDeep++,跳出一次scan方法时curDeep--

public class Filer {    ...    int curDeep;//节点深度---->[Filer#scan]---------------private void scan(FileNode node) {    File file = node.file;    if (file.isFile()) {//如果节点是文件        return;    }    File[] files = file.listFiles();    for (File f : files) {        FileNode child = new FileNode(f);        child.deep = curDeep;        node.child.add(child);        System.out.println(child.file.getAbsolutePath() + "--" + child.deep);        if (f.isDirectory()) {            dirCount++;//每调用一次说明有一个文件夹            curDeep++;            scan(child);        } else {            fileCount++;//每调用一次说明有一个文件            for (FileFilter filter : mFilters) {                if (filter != null && filter.iCanGo(f.getAbsolutePath())) {                    filter.filter(f);                }            }            length += f.length();        }    }    curDeep--;}/** * 文件节点 */private class FileNode {    ...    public int deep;//深度}复制代码

2.修改接口

现在想把deep这个参数传出去...有两个方法,一种:修改接口!!!

第二种:新建接口,还好实现类不是很多,这里改一下接口吧...

/** * 作者:张风捷特烈 * 时间:2019/2/13/013:14:31 * 邮箱:1981462002@qq.com * 说明:文件过滤接口 */public interface FileFilter {    /**     * 根据路径判断是否过滤出     * @param path 路径     * @return 是否可以执行filter     */    boolean iCanGo(File path);    /**     * 过滤的逻辑操作     * @param file 文件     * @param deep 该文件深度     */    void filter(File file, int deep);}---->[Filer#scan]---------------------------private void scan(FileNode node) {    ...    for (File f : files) {        FileNode child = new FileNode(f);        child.deep = curDeep;        node.child.add(child);        for (FileFilter filter : mFilters) {            if (filter != null && filter.iCanGo(f)) {                filter.filter(child.file, child.deep);//回调出去深度            }        }    ...}复制代码

3.打印目录结构

一直觉得目录结构挺帅气,今天总算自己弄出来了,可喜可贺,可喜可贺

-----------------创建目录结构过滤器----------------|--这里iCanGo返回true,也就是畅通无阻,相当于一个监听器/** * 作者:张风捷特烈 * 时间:2019/2/13/013:10:59 * 邮箱:1981462002@qq.com * 说明:创建目录结构 */public class StructureBuilder implements FileFilter {    String prefix;    String blank;    StringBuilder sb = new StringBuilder("目录结构:\n");    public String getStructure() {        return sb.toString();    }    public StructureBuilder() {        this("|---", "    ");    }    public StructureBuilder(String prefix, String blank) {        this.prefix = prefix;        this.blank = blank;    }    @Override    public boolean iCanGo(File file) {        return true;    }    @Override    public void filter(File file, int deep) {        sb                .append(blankBuilder(blank, deep))                .append(prefix)                .append(file.getName())                .append("\n");    }    private static StringBuilder blankBuilder(String symbol, int num) {        StringBuilder stringBuffer = new StringBuilder();        for (int i = 0; i < num; i++) {            stringBuffer.append(symbol);        }        return stringBuffer;    }}---->[使用]---------Filer filer = new Filer("J:\\C++");StructureBuilder structureBuilder = new StructureBuilder();filer.addFilter(structureBuilder);filer.scan();System.out.println(structureBuilder.getStructure());复制代码

这样,样式随便你来定义:new StructureBuilder("|---","····")


4.保存文件目录树

在根目录下保存一个文件目录树,这样方便查看,也让你知道大概这个文件夹怎么样

有多少文件,字符串在这里,你可以随意分析,玩弄,是不是很有趣

---->[StructureBuilder#writeFile]---------------------------/** * 将文件结构写入文件 * @param file 文件 */public void writeFile(File file) {    FileWriter fw = null;    try {        fw = new FileWriter(file);        String time = new SimpleDateFormat("yyyy-MM-dd kk:mm:ss", Locale.CHINA)                .format(System.currentTimeMillis());        fw.write("张风捷特烈--修改于" + time + "\n");        fw.write(sb.toString());    } catch (IOException e) {        e.printStackTrace();    } finally {        try {            if (fw != null) {                fw.close();            }        } catch (IOException e) {            e.printStackTrace();        }    }}复制代码

看这个目录里有11W个文件,好吧,吓我一跳,生成也只用了7秒多


5.创建json格式的文件描述文件夹

没想到用个节点之后这么方便,Gosn秒出结构

依赖:implementation 'com.google.code.gson:gson:2.8.5'
好了,Json在手,去解析着玩吧

Filer filer = new Filer("J:\\edite");filer.scan();String json = new GsonBuilder().setPrettyPrinting().create().toJson(filer);System.out.println(json);复制代码
{  "file": {    "path": "J:\\edite"  },  "dirCount": 4,  "fileCount": 6,  "length": 11890,  "curDeep": -1,  "root": {    "child": [      {        "child": [],        "file": {          "path": "J:\\edite\\edit.jar"        },        "deep": 0      },      {        "child": [],        "file": {          "path": "J:\\edite\\main.txt"        },        "deep": 0      },      {        "child": [],        "file": {          "path": "J:\\edite\\structure.txt"        },        "deep": 0      },      {        "child": [          {            "child": [              {                "child": [                  {                    "child": [],                    "file": {                      "path": "J:\\edite\\top\\toly\\界面编程GUI\\Edit.java"                    },                    "deep": 3                  },                  {                    "child": [],                    "file": {                      "path": "J:\\edite\\top\\toly\\界面编程GUI\\FileHelper.java"                    },                    "deep": 3                  },                  {                    "child": [],                    "file": {                      "path": "J:\\edite\\top\\toly\\界面编程GUI\\IOUtils.java"                    },                    "deep": 3                  }                ],                "file": {                  "path": "J:\\edite\\top\\toly\\界面编程GUI"                },                "deep": 2              }            ],            "file": {              "path": "J:\\edite\\top\\toly"            },            "deep": 1          }        ],        "file": {          "path": "J:\\edite\\top"        },        "deep": 0      }    ],    "file": {      "path": "J:\\edite"    },    "deep": 0  }}复制代码

6.还是自己优化一下json吧

上面的json看着不爽,把root字段屏蔽掉,看一下本项目目录信息吧

保存到文件夹里也是一样的,这里就不演示了

/** * 作者:张风捷特烈 * 时间:2019/2/13/013:10:59 * 邮箱:1981462002@qq.com * 说明:创建目录JSON结构 */public class JsonDirBuilder implements FileFilter {    List
dirs; List
files; public String getStructure() { return new GsonBuilder().setPrettyPrinting().create().toJson(dirs); } public JsonDirBuilder() { dirs = new ArrayList<>(); files = new ArrayList<>(); } @Override public boolean iCanGo(File file) { return true; } @Override public void filter(File file, int deep) { Filer filer = new Filer(file.getAbsolutePath()); filer.scan(); filer.curDeep = deep; if (file.isDirectory()) { dirs.add(filer); } else { files.add(filer); } } /** * 将文件结构写入文件 * * @param file 文件 */ public void writeFile(File file) { FileWriter fw = null; try { fw = new FileWriter(file); String time = new SimpleDateFormat("yyyy-MM-dd kk:mm:ss", Locale.CHINA) .format(System.currentTimeMillis()); fw.write("张风捷特烈--修改于" + time + "\n"); fw.write(getStructure()); } catch (IOException e) { e.printStackTrace(); } finally { try { if (fw != null) { fw.close(); } } catch (IOException e) { e.printStackTrace(); } } }}复制代码
[  {    "file": {      "path": "J:\\FileUnit\\file_java\\file\\out"    },    "dirCount": 7,    "fileCount": 12,    "length": 22907,    "curDeep": 0  },  {    "file": {      "path": "J:\\FileUnit\\file_java\\file\\out\\production"    },    "dirCount": 6,    "fileCount": 12,    "length": 22907,    "curDeep": 1  },  {    "file": {      "path": "J:\\FileUnit\\file_java\\file\\out\\production\\classes"    },    "dirCount": 5,    "fileCount": 12,    "length": 22907,    "curDeep": 2  },  {    "file": {      "path": "J:\\FileUnit\\file_java\\file\\out\\production\\classes\\app"    },    "dirCount": 1,    "fileCount": 4,    "length": 9499,    "curDeep": 3  },  {    "file": {      "path": "J:\\FileUnit\\file_java\\file\\out\\production\\classes\\bean"    },    "dirCount": 1,    "fileCount": 1,    "length": 2259,    "curDeep": 3  },  {    "file": {      "path": "J:\\FileUnit\\file_java\\file\\out\\production\\classes\\filter"    },    "dirCount": 1,    "fileCount": 6,    "length": 9800,    "curDeep": 3  },  {    "file": {      "path": "J:\\FileUnit\\file_java\\file\\out\\production\\classes\\utils"    },    "dirCount": 1,    "fileCount": 1,    "length": 1349,    "curDeep": 3  },  {    "file": {      "path": "J:\\FileUnit\\file_java\\file\\src"    },    "dirCount": 11,    "fileCount": 11,    "length": 18285,    "curDeep": 0  },  {    "file": {      "path": "J:\\FileUnit\\file_java\\file\\src\\main"    },    "dirCount": 7,    "fileCount": 11,    "length": 18285,    "curDeep": 1  },  {    "file": {      "path": "J:\\FileUnit\\file_java\\file\\src\\main\\java"    },    "dirCount": 5,    "fileCount": 11,    "length": 18285,    "curDeep": 2  },  {    "file": {      "path": "J:\\FileUnit\\file_java\\file\\src\\main\\java\\app"    },    "dirCount": 1,    "fileCount": 3,    "length": 7919,    "curDeep": 3  },  {    "file": {      "path": "J:\\FileUnit\\file_java\\file\\src\\main\\java\\bean"    },    "dirCount": 1,    "fileCount": 1,    "length": 1935,    "curDeep": 3  },  {    "file": {      "path": "J:\\FileUnit\\file_java\\file\\src\\main\\java\\filter"    },    "dirCount": 1,    "fileCount": 6,    "length": 7477,    "curDeep": 3  },  {    "file": {      "path": "J:\\FileUnit\\file_java\\file\\src\\main\\java\\utils"    },    "dirCount": 1,    "fileCount": 1,    "length": 954,    "curDeep": 3  },  {    "file": {      "path": "J:\\FileUnit\\file_java\\file\\src\\main\\resources"    },    "dirCount": 1,    "fileCount": 0,    "length": 0,    "curDeep": 2  },  {    "file": {      "path": "J:\\FileUnit\\file_java\\file\\src\\test"    },    "dirCount": 3,    "fileCount": 0,    "length": 0,    "curDeep": 1  },  {    "file": {      "path": "J:\\FileUnit\\file_java\\file\\src\\test\\java"    },    "dirCount": 1,    "fileCount": 0,    "length": 0,    "curDeep": 2  },  {    "file": {      "path": "J:\\FileUnit\\file_java\\file\\src\\test\\resources"    },    "dirCount": 1,    "fileCount": 0,    "length": 0,    "curDeep": 2  }]复制代码
7.点睛之笔

写了老半天,现在把写的东西考到build.gradle里,当插件用

Groovy完全兼容java,所以,都考进去就行了,上面的所以都可以当脚本用
Gradle真是挺好玩的,以后有什么想偷懒的,写个java版的,在一贴,就能当脚本用
今天东西有点杂,好好消化消化吧,感觉发现了新天地

--------------------------插件-------------------------------------------apply plugin: ListDirPlugin//声明使用插件listDir {//根据拓展参数来自定义文件夹    path = 'J:\\FileUnit\\file_java\\file'}--------------------------插件书写-------------------------------------------public class Filer {    private File file;//文件夹名    private int dirCount = 1;//子文件夹数量---不包括自身    private int fileCount;//文件的个数    private long length; //文件夹大小    //过滤器集合    private transient ArrayList
mFilters = new ArrayList<>(); public int curDeep;//节点深度 public void addFilter(FileFilter countFilter) { mFilters.add(countFilter); } public File getFile() { return file; } public int getDirCount() { return dirCount; } public int getFileCount() { return fileCount; } public long getLength() { return length; } private transient FileNode root;//根节点 public Filer(String rootPath) { file = new File(rootPath); root = new FileNode(file); } public void scan() { scan(root); } public void scan(FileNode node) { File file = node.file; if (file.isFile()) {//如果节点是文件 return; } File[] files = file.listFiles(); for (File f : files) { FileNode child = new FileNode(f); child.deep = curDeep; node.child.add(child); for (FileFilter filter : mFilters) { if (filter != null && filter.iCanGo(f)) { filter.filter(child.file, child.deep); } } if (f.isDirectory()) { dirCount++;//每调用一次说明有一个文件夹 curDeep++; scan(child); } else { fileCount++;//每调用一次说明有一个文件 length += f.length(); } } curDeep--; } /** * 将Filer的数据进行初始化 * 遍历当前节点 * * @param target * @return */ private long traverse(FileNode target) {//--------瞎猫碰到死耗子 if (target.child == null) { return length; } if (target.file.isDirectory()) { dirCount++;//每调用一次说明有一个文件夹 for (FileNode node : target.child) { length += traverse(node); } return length; } else { fileCount++;//每调用一次说明有一个文件 return length + target.file.length(); } } /** * 文件节点 */ private class FileNode { public ArrayList
child;//子节点集合 public File file; //文件路径 public int deep;//深度 public FileNode(File file) { this.file = file; child = new ArrayList<>(4); } } @Override public String toString() { return "Filer{" + "file=" + file + ", dirCount=" + dirCount + ", fileCount=" + fileCount + ", length=" + length + ", curDeep=" + curDeep + '}'; }}/** * 作者:张风捷特烈 * 时间:2019/2/13/013:14:31 * 邮箱:1981462002@qq.com * 说明:文件过滤接口 */public interface FileFilter { /** * 根据路径判断是否过滤出 * @param path 路径 * @return 是否可以执行filter */ boolean iCanGo(File path); /** * 过滤的逻辑操作 * @param file 文件 * @param deep 该文件深度 */ void filter(File file, int deep);}/** * 作者:张风捷特烈 * 时间:2019/2/13/013:10:59 * 邮箱:1981462002@qq.com * 说明:创建目录结构 */public class StructureBuilder implements FileFilter { String prefix; String blank; StringBuilder sb = new StringBuilder("目录结构:\n"); public String getStructure() { return sb.toString(); } public StructureBuilder() { this("|---", "····"); } public StructureBuilder(String prefix, String blank) { this.prefix = prefix; this.blank = blank; } @Override public boolean iCanGo(File file) { return true; } @Override public void filter(File file, int deep) { sb .append(blankBuilder(blank, deep)) .append(prefix) .append(file.getName()) .append("\n"); } private static StringBuilder blankBuilder(String symbol, int num) { StringBuilder stringBuffer = new StringBuilder(); for (int i = 0; i < num; i++) { stringBuffer.append(symbol); } return stringBuffer; } /** * 将文件结构写入文件 * @param file 文件 */ public void writeFile(File file) { FileWriter fw = null; try { fw = new FileWriter(file); String time = new SimpleDateFormat("yyyy-MM-dd kk:mm:ss", Locale.CHINA) .format(System.currentTimeMillis()); fw.write("张风捷特烈--修改于" + time + "\n"); fw.write(sb.toString()); } catch (IOException e) { e.printStackTrace(); } finally { try { if (fw != null) { fw.close(); } } catch (IOException e) { e.printStackTrace(); } } }}//----------------------------以下是插件部分--------------------------------class ListDirPlugin implements Plugin
{ //该接口定义了一个apply()方法,在该方法中,我们可以操作Project, //比如向其中加入Task,定义额外的Property等。 void apply(Project project) { //加载Extension project.extensions.create("listDir", MkDirPluginPluginExtension) //使用Extension配置信息 project.task('listDirTask') << { String path = project.listDir.path Filer filer = new Filer(path); StructureBuilder structureBuilder = new StructureBuilder("|---","...."); filer.addFilter(structureBuilder); filer.scan(); System.out.println(structureBuilder.getStructure()); File file = new File(filer.getFile(), "structure.txt"); structureBuilder.writeFile(file); } }}class MkDirPluginPluginExtension {//拓展参数 String path = ''}复制代码

后记:捷文规范

1.本文成长记录及勘误表
项目源码 日期 附录
V0.1-- 2018-2-13

发布名:杂篇-从文件操作来发起的杂谈[-File-]

捷文链接:

2.更多关于我
笔名 QQ 微信
张风捷特烈 1981462002 zdl1994328

我的github:

我的简书:
我的掘金:
个人网站:

3.声明

1----本文由张风捷特烈原创,转载请注明

2----欢迎广大编程爱好者共同交流
3----个人能力有限,如有不正之处欢迎大家批评指证,必定虚心改正
4----看到这里,我在此感谢你的喜欢与支持

你可能感兴趣的文章
第31讲 | 数字货币钱包服务
查看>>
P2073 送花
查看>>
iOS端项目注释规范附统一代码块
查看>>
HTTP深入浅出 http请求
查看>>
为YUM设置代理的方法
查看>>
Java 编程的动态性 第1 部分: 类和类装入--转载
查看>>
【转】持久化消息队列之MEMCACHEQ
查看>>
Dom4j学习笔记
查看>>
C语言 HTTP上传文件-利用libcurl库上传文件
查看>>
[MEAN Stack] First API -- 7. Using Route Files to Structure Server Side API
查看>>
调试逆向分为动态分析技术和静态分析技术(转)
查看>>
业务对象和BAPI
查看>>
微软职位内部推荐-Senior Software Engineer
查看>>
程序中的魔鬼数字
查看>>
session cookie
查看>>
$.extend({},defaults, options) --(初体验三)
查看>>
android 一步一步教你集成tinker(热修复)
查看>>
到底有多少内存
查看>>
centos7.3 安装ovirt-engine4.0 版本
查看>>
Openstack的环境的Mitaka部署环境服务,实例(1)
查看>>