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

零、前言

说一下本篇的初衷: 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<FileNode> 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.86621KBSystem.out.println(Formater.format_B_KB_MB_GB(length));//5long modifyTime = filer.getFile().lastModified();//2018-10-06 15:19:39System.out.println(Formater.format_yyyy_MM_dd_kk_mm_ss(modifyTime));//5System.out.println(filer.getFile().getName());//editeSystem.out.println(+filer.getDirCount()+"个文件夹");//3System.out.println(filer.getFileCount()+"个文夹");//5System.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<String> suffixs;public Set<String> 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<String> 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<String> suffixs;public Set<String> 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,是othersuffixs.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<String> suffixs;public Set<String> getSuffixs() {return suffixs;}public SuffixFilter() {suffixs = new HashSet<>();}@Overridepublic 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,是othersuffixs.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<String> javaFiles;public ArrayList<String> getJavaFiles() {return javaFiles;}public JavaFilter() {javaFiles = new ArrayList<>();}@Overridepublic boolean iCanGo(File file) {String path = file.getAbsolutePath();String suffix = path.substring(path.lastIndexOf(".") + 1);return suffix.equals("java");}@Overridepublic 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<String> javaFiles;private String type;public TypeFilter(String type) {this.type = type;javaFiles = new ArrayList<>();}public ArrayList<String> getJavaFiles() {return javaFiles;}@Overridepublic boolean iCanGo(File file) {String path = file.getAbsolutePath();String suffix = path.substring(path.lastIndexOf(".") + 1);return suffix.equals(type);}@Overridepublic void filter(File file) {javaFiles.add(file.getAbsolutePath());}
}
复制代码

6.批量修改操作

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

Filer filer = new Filer("J:\\edite");
filer.setFilter(new FileFilter() {@Overridepublic boolean iCanGo(String path) {String path = file.getAbsolutePath();String suffix = path.substring(path.lastIndexOf(".") + 1);return suffix.equals("java");}@Overridepublic 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<FileFilter> 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;}@Overridepublic boolean iCanGo(File file) {return true;}@Overridepublic 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<Filer> dirs;List<Filer> files;public String getStructure() {return new GsonBuilder().setPrettyPrinting().create().toJson(dirs);}public JsonDirBuilder() {dirs = new ArrayList<>();files = new ArrayList<>();}@Overridepublic boolean iCanGo(File file) {return true;}@Overridepublic 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<FileFilter> 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<FileNode> child;//子节点集合public File file; //文件路径public int deep;//深度public FileNode(File file) {this.file = file;child = new ArrayList<>(4);}}@Overridepublic 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;}@Overridepublic boolean iCanGo(File file) {return true;}@Overridepublic 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<Project> {//该接口定义了一个apply()方法,在该方法中,我们可以操作Project,//比如向其中加入Task,定义额外的Property等。void apply(Project project) {//加载Extensionproject.extensions.create("listDir", MkDirPluginPluginExtension)//使用Extension配置信息project.task('listDirTask') << {String path = project.listDir.pathFiler 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-]
捷文链接:www.jianshu.com/u/e4e52c116…

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

我的github:github.com/toly1994328
我的简书:www.jianshu.com/u/e4e52c116…
我的掘金:juejin.im/user/5b42c0…
个人网站:www.toly1994.com

3.声明

1----本文由张风捷特烈原创,转载请注明
2----欢迎广大编程爱好者共同交流
3----个人能力有限,如有不正之处欢迎大家批评指证,必定虚心改正
4----看到这里,我在此感谢你的喜欢与支持

杂篇-从整理文件发起的杂谈[-File-]相关推荐

  1. 如何用python整理文件夹_python按照文件创建日期整理文件至文件夹

    # -*- coding: utf-8 -*- # @Time : 2019-02-15 13:31 # @Author : cxa # @File : sortbydate.py # @Softwa ...

  2. 文件句柄(file handles) 文件描述符(file descriptors)

    欢迎支持笔者新作:<深入理解Kafka:核心设计与实践原理>和<RabbitMQ实战指南>,同时欢迎关注笔者的微信公众号:朱小厮的博客. 欢迎跳转到本文的原文链接:https: ...

  3. Python自动化整理文件,还增加了可视化GUI界面

    有时候,我们写了一些简单.有用的小代码. 此时,如果能够有一个可视化GUI界面,是不是显得很舒服.今天介绍的一个Python库,超级牛逼,几行代码就可以实现一个可视化界面! Gooey介绍 这里用到的 ...

  4. 弹性文件服务(Scalable File Service,SFS)

    弹性文件服务(Scalable File Service,SFS) 弹性文件服务(Scalable File Service,SFS)提供按需扩展的高性能文件存储(NAS),可为云上多个弹性云服务器( ...

  5. python文件整理程序_Python实现自动整理文件的脚本

    前言 工作上的文档和资料好几个月没整理了,因为平常太忙都是随手往桌面丢.整个桌面杂乱无章全是文档和资料.几乎快占满整个屏幕了,所有我必须要整理一下了.但是手动整理太费时间了,于是我想到了python. ...

  6. contig命令整理文件碎片

    在用Grub启动Windows操作系统镜像的时候通常会用 map /Windows8.iso (hd32) 这条命令,它其实是将Windows8.iso虚拟成一个CDROM,而(hd32)指的是CDR ...

  7. python自动整理文件,就这么简单

    平时工作没有养成分类的习惯,整个桌面杂乱无章都是文档和资料,几乎快占满整个屏幕了.所以必须要整理一下了,今天我们来看下用python如何批量将不同后缀的文件移动到同一文件夹. 演示效果: 使用前 使用 ...

  8. 用Python制作可视化GUI界面,顺便实现自动分类整理文件

    有时候,我们写了一些简单.有用的小代码.此时,如果能够有一个可视化GUI界面,是不是显得很舒服.今天介绍的一个Python库,超级牛逼,几行代码就可以实现一个可视化界面! 应朋友私信要求,开通技术交流 ...

  9. python3 自动整理文件(超简单代码)

    思路: 1.在该文件夹里面创建子文件夹 2.判断该文件夹里面所有文件的格式,也就是什么后缀名 3.将文件进行重命名并放入刚创建好的子文件夹中 4.两种整理办法: (1)利用shutil.copy这个函 ...

最新文章

  1. 使用rsync同步linux服务器上的文件到windows上
  2. 计算机的命令函数,数学建模的常用的命令和基本函数..doc
  3. snpeff注释变异(variants)
  4. HDU - 6602 Longest Subarray(线段树+思维)
  5. 用计算机完成下表的视距测量计算公式,测量学计算题.doc
  6. 个人中心的html,个人中心.html
  7. Linux中的shell正则表达式详解
  8. 元素的水平垂直居中解决方法
  9. 运用ffmpeg生成MP4文件
  10. 学生网上评教系统php,学生评教系统设计与实现.doc
  11. 机器学习笔记(十五):人脸识别
  12. sql 只要一个字段相同则只显示一条数据_sql 有一个字段内容重复的 只显示一条的方法...
  13. DIP 电源跌落瞬时中断(Voltage dips)
  14. MySQL可视化工具下载安装及连接
  15. VMware ThinApp应用程序虚拟化工具
  16. 保定工程技术学校网络计算机,保定工程技术学校2021年有哪些专业
  17. freeswitch添加G729编解码模块
  18. 博后招募 | 浙江大学陈华钧教授招聘知识图谱等方向博后及算法工程师
  19. 英语3500词(二) your dream lover主题 (2022.1.14)
  20. html中数字的格式设置,fmt:formatNumber 标签 | 菜鸟教程

热门文章

  1. DataLoader worker (pid(s) 11404, 1168, 15692, 13308) exited unexpectedly
  2. 张亚勤院士谈“智能计算新趋势”
  3. 图灵奖得主杨立昆:人工智能比你更聪明吗?
  4. 【人工智能】人工智能革命与机遇
  5. 揭秘Facebook SLAM技术,如何为人们生活增添奇幻的艺术色彩?
  6. 不敢回国的硅谷程序员们!
  7. 12月31日写成13月1日引发重大 Bug,程序员新年就要被“祭天”?
  8. 面试官:兄弟,说说 ArrayList 和 LinkedList 有什么区别
  9. 分布式 RPC 框架
  10. PHP的学习--Traits新特性