有些東西很簡單,簡單到你不想去想,比如:為什麼天是藍的?--侷限物語
零、前言
說一下本篇的初衷: 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.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<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,是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<String> suffixs;
public Set<String> 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<String> javaFiles;
public ArrayList<String> 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<String> javaFiles;
private String type;
public TypeFilter(String type) {
this.type = type;
javaFiles = new ArrayList<>();
}
public ArrayList<String> 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<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;
}
@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<Filer> dirs;
List<Filer> 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<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);
}
}
@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<Project> {
//該介面定義了一個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-]
捷文連結:www.jianshu.com/u/e4e52c116…
2.更多關於我
筆名 | 微信 | |
---|---|---|
張風捷特烈 | 1981462002 | zdl1994328 |
我的github:github.com/toly1994328
我的簡書:www.jianshu.com/u/e4e52c116…
我的掘金:juejin.im/user/5b42c0…
個人網站:www.toly1994.com
3.宣告
1----本文由張風捷特烈原創,轉載請註明
2----歡迎廣大程式設計愛好者共同交流
3----個人能力有限,如有不正之處歡迎大家批評指證,必定虛心改正
4----看到這裡,我在此感謝你的喜歡與支援