Some things are so simple that you don't want to think about them, like: Why is the sky blue? -- The story of limitations

Zero, preface,

Coder disk as a working disk is a bit messy, I want to tidy it up

Also want to seek a convenient management project idea, since the File class play familiar, why not play with the natural recursion of File, and then familiar with recursion is also good, so that there is this article, this article is a bit long, the play in the back —- note: the focus of this article is not the operation, but the idea


Create the Filer class

Java’s File object provides only basic information, and rightly so

It feels like it can be encapsulated to provide more information, such as the following, folder size, number of subfiles, etc


1. Here’s a simple example: The directory structure is as follows:
| - edite | - top | - toly | - GUI interface programming | - Edit the Java | - FileHelper. Java | - IOUtils. Java | - Edit. The jar | - main. TXTCopy the code

2. Encapsulate Filer information

First realize the number of subfolders, files, folder size three properties

public class Filer { private String name; // Folder name private int dirCount; Private int fileCount; private int fileCount; // Number of files private long length; Public File getFile() {return File; } public int getDirCount() { return dirCount - 1; } public int getFileCount() { return fileCount; } public long getLength() { return length; }}Copy the code

3. Define the file node class

So if you have multiple files in one folder, let’s do an ArrayList,

Given that by default the initial array of ArrayList is 10, let’s take four (probably just one or two files per folder).

Private class FileNode {public ArrayList<FileNode> child; // Child node collection public File File; Public FileNode(File File) {this.file = File; child = new ArrayList<>(4); }}Copy the code

4.Filer initialization
private FileNode root; Public Filer(String rootPath) {file = new file (rootPath); root = new FileNode(file); // Initialize the root node}Copy the code

5. Scan files

You can use the following analysis to debug your own walk

public Filer(String rootPath) { file = new File(rootPath); root = new FileNode(file); scan(root); // Scan the root directory} private void scan(FileNode node) {File File = node.file; If (file.isfile ()) {// if the node is a file return; } File[] files = file.listFiles(); for (File f : files) { FileNode child = new FileNode(f); node.child.add(child); if (f.isDirectory()) { scan(child); }}}Copy the code

The first time scan is called, if it is a folder, it traverses the folder,

Whatever files or folders are in there are added to the child

When a folder is encountered, a scan is triggered to scan the folder, which is the simplest recursion

There is no return value, just the triggering action (actually every time the triggering scan method call completes, there is the step of the method out of the stack)

So a tree structure is formed


6. Since nodes are connected to the tree

You can do more things during the scan, such as maintaining those three member variables

private void scan(FileNode node) { File file = node.file; If (file.isfile ()) {// if the node is a file return; } File[] files = file.listFiles(); for (File f : files) { FileNode child = new FileNode(f); node.child.add(child); if (f.isDirectory()) { dirCount++; // Each call indicates a folder scan(child); } else { fileCount++; Length += f.length(); // Maintain length}}}Copy the code

7. Call

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.86621 KB 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()+" folders "); //3 system.out.println (filer.getFilecount ()+" filecount "); //5 System.out.println(filer.getFileFilter().get(0).count); / / 5}}Copy the code

Take a look at it in a larger folder: 7 seconds or more is a bit slow, compared to 9 seconds for the computer’s own viewer, so that’s ok


Two, armed

1. Collect statistics on file types in folders

When you think about it, it takes 7 seconds to get three properties, and you’re traversing all the files on one side

Now it’s not too much to ask to see how many types of files there are, but it’s easy to think about it, just look at the suffix

public Filer(String rootPath) { mSet = new HashSet<>(); . } private void scan(FileNode node) { File file = node.file; If (file.isfile ()) {// if the node is a file return; } File[] files = file.listFiles(); for (File f : files) { FileNode child = new FileNode(f); node.child.add(child); if (f.isDirectory()) { dirCount++; // Each call indicates a folder scan(child); } else { fileCount++; String fileName = f.getname (); String fileName = f.getname (); String suffix = fileName.substring(fileName.lastIndexOf(".") + 1); mSet.add(suffix); length += f.length(); }}}Copy the code

2. Emergence of strategies

There’s a problem with that. Maybe I’ve been thinking too much about design patterns lately

Filer has already done a good job of scanning it, but it’s not nice to have an extra member variable mSet in Filer, and the else three lines of code are not elegant, and if you need to change them, where to find them, and if you have more code, where to find these three lines! Why not extract the strategy?

/** * Author: Zhang Feng jiete Lie * Time: 2019/2/13/013:13:44 * Email: [email protected] * Description: 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(); } -- -- -- - > [use] -- -- -- -- -- -- -- -- -- -- -- -- -- Filer Filer = new Filer (" J: \ \ edite "); SuffixFilter filter = new SuffixFilter(); filer.setFilter(filter); // Set the filter filer.scan(); Set<String> suffixs = filter.getSuffixs(); For (String suffix: suffixs) {system.out. print(suffix+", "); }Copy the code


3. The advantages of separation emerge when changes are needed

In this way, the action of getting the Filer class and getting the file type are decoupled, and the Filter is only concerned with scanning tasks

For example, some file names do not have a suffix, so you need to change the policy, can not count as one file, right? There are specialized classes, just modify SuffixFilter’s filtering methods, which is much better than Filer

/** * Author: Zhang Feng jiete Lie * Time: 2019/2/13/013:13:44 * Email: [email protected] * Description: 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) {// If the length is greater than 10, it is other suffixs.add(suffix); }else { suffixs.add("other"); }}}Copy the code


4. Abstraction and extension

Since it is a strategy, there can be a variety of, so abstract out of the common, custom personality to expand

Obviously, there is a public abstract method, filter(File), and since it is a filter, there should be filter conditions

/** * Author: Zhang Feng jiete Lie * Time: 2019/2/13/013:14:31 * Email: [email protected] * Description: File filtering interface */ public interface FileFilter {/** * Check whether the @param file file is filtered by the path * @return Whether the filter */ Boolean iCanGo(file) can be executed  file); /** * filter logic operation * @param file */ void filter(file file); } /** * Author: Zhang Feng jiete Lie * Time: 2019/2/13/013:13:44 * Email: [email protected] * Description: */ 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) {// If the length is greater than 10, it is 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); }... }Copy the code

5. Function expansion based on interface

Well why do I want to add an interface, is my first learning Java when a big question, resulting in my design pattern confused

Now you want to add a way to get all the Java files in a folder, and the interface is very handy

/** * Author: Zhang Feng jiete Lie * Time: 2019/2/13/013:10:59 * Email: [email protected] * Description: */ 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()); }} - > [use] -- -- -- -- -- -- -- -- -- -- Filer Filer = new Filer (J: \ \ "lot"); JavaFilter javaFilter = new JavaFilter(); filer.setFilter(javaFilter); filer.scan(); for (String s : javaFilter.getJavaFiles()) { System.out.println(s); }Copy the code

Visible filtering has been separated from Filer, extending the ability to view all Java files

Without modifying any code in Filer, it is a good iCanGo method for Filer to control filtering, filter is used to manipulate… One control mage, one output warrior, all right

Of course, you can also make types into parameters, through construction, which is more convenient

/** * Author: Zhang Feng jiete Lie * Time: 2019/2/13/013:10:59 * Email: [email protected] * Description: Public class TypeFilter implements FileFilter {private ArrayList<String> javaFiles; 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()); }}Copy the code

6. Modify operations in batches

A lot of times it feels like a relay race, where once you pass the stick to the next person, you don’t have to run

Filer is like this, I send you the files that I’m iterating over, you can do what you want, it’s not my business. It’s kind of like the server sends you the data, you can do what you want with it. Now I want to add a line at the end of all the Java files in a folder: I’m the boss of what to do, you don’t even have to create a new class, just write an anonymous inner class, get the file, write it!

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();Copy the code

In this way, batch name change is not easy


7. Multiple filters

Anyway, I’ve traversed it, so I don’t need to use it, so I need to use a few more filters, a few more operations

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); }}... -- -- -- - > [use] -- -- -- -- -- 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); }Copy the code

3. Back to business

1. Add a node depth field and maintain it

CurDeep — whenever folder curDeep++ is displayed, curDeep– is displayed when scan is displayed

public class Filer { ... int curDeep; / / depth of the node - > [Filer# scan] -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- private void scan (FileNode node) {File File = node. The File; If (file.isfile ()) {// if the node is a file 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++; 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; } / / depthCopy the code

2. Modify the interface

Now I want to pass out the parameter “deep”… There are two methods, one is: modify the interface!!

The second kind: new interface, but not a lot of implementation class, here to change the interface…

/** * Author: Zhang Feng jiete Lie * Time: 2019/2/13/013:14:31 * Email: [email protected] * Description: File filtering interface */ public interface FileFilter {/** * Check whether the File is filtered by the path * @param path path * @return Whether the filter */ Boolean iCanGo(File)  path); / / void filter(file file, int 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); // Call back to the dedepth}}... }Copy the code

3. Print the directory structure

I have always felt that the directory structure is very handsome, and today I finally got it out by myself. Congratulations, congratulations

-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- create the directory structure filter -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - | - here iCanGo returns true, that is clear, the equivalent of a listener / * * * the author: packer fierce * jet time: 2019/2/13/013:10:59 * Email: [email protected] * Note: */ public class StructureBuilder implements FileFilter {String prefix; String blank; StringBuilder sb = new StringBuilder(" directory structure :\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; }} - > [use] -- -- -- -- -- -- -- -- -- Filer Filer = new Filer (J: \ \ c + + ""); StructureBuilder structureBuilder = new StructureBuilder(); filer.addFilter(structureBuilder); filer.scan(); System.out.println(structureBuilder.getStructure());Copy the code

So defined style you like: new StructureBuilder (” | — – “, “… “)


4. Save the file directory tree

Keep a file directory tree in the root directory so that you can easily view it and know what the folder looks like

How many files are there? Strings are here, and you can analyze them and play with them. Isn’t that interesting

-- -- -- - > [StructureBuilder# writeFile] -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- / written to the file * @ * * * the file structure param file 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(" zhang Feng Jettison -- modified to "+ time + "\n"); fw.write(sb.toString()); } catch (IOException e) { e.printStackTrace(); } finally { try { if (fw ! = null) { fw.close(); } } catch (IOException e) { e.printStackTrace(); }}}Copy the code

Look at this directory has 11W files, well, I’m surprised, also generated in just over 7 seconds


5. Create a file description folder in JSON format

Unexpectedly after using a node so convenient, Gosn seconds out of the structure

Rely on: implementation ‘com. Google. Code. Gson: gson: 2.8.5’ ok, Json in hand, to dissect the play

Filer filer = new Filer("J:\\edite");
filer.scan();
String json = new GsonBuilder().setPrettyPrinting().create().toJson(filer);
System.out.println(json);
Copy the code
{ "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 interface programming \ \ Edit Java"}, "deep" : 3}, {" child ": []," file ": {" path" : J: \ \ edite \ \ "top \ \ toly \ \ GUI interface programming \ \ FileHelper Java"}, "deep" : 3}, {" child ": []," file ": {" path" : J: \ \ edite \ \ "top \ \ toly \ \ GUI interface programming \ \ IOUtils Java"}, "deep" : 3}], "file" : {" path ": J: \ \ edite \ \ "top \ \ toly \ \ GUI interface programming"}, "deep" : 2}], "file" : {" path ":" J: \ \ edite \ \ top \ \ toly "}, "deep" : 1}], "file" : { "path": "J:\\edite\\top" }, "deep": 0 } ], "file": { "path": "J:\\edite" }, "deep": 0 } }Copy the code

6. Optimize your JSON

The above JSON looks bad, so let’s leave the root field out and take a look at the project directory information

It’s the same thing if you save it to a folder, which I won’t do here

/** * Author: Zhang Feng jiete Lie * Time: 2019/2/13/013:10:59 * Email: [email protected] * Description: */ 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); }} /** * Write the file structure to the file ** @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(" zhang Feng Jettison -- modified to "+ time + "\n"); fw.write(getStructure()); } catch (IOException e) { e.printStackTrace(); } finally { try { if (fw ! = null) { fw.close(); } } catch (IOException e) { e.printStackTrace(); }}}}Copy the code
[
  {
    "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
  }
]

Copy the code
7. The finishing touch

I’ve been writing for a long time, but now I’m going to test it in build.gradle and use it as a plugin

In the future, if you want to write a Java version, you can use it as a script. Today’s stuff is a bit messy, let’s digest it, and feel like you’ve discovered a new world

/ / / / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- plug-ins -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- the apply the plugin: Path = 'J:\\FileUnit\\file_java\\file'} = 'J:\\FileUnit\\file_java\\file'} / / / / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - the plugin writing -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- the public class Filer {private File File; Private int dirCount = 1; Private int fileCount; private int fileCount; // Number of files private long length; Private transient ArrayList<FileFilter> mFilters = new ArrayList<>(); private transient ArrayList<FileFilter> mFilters = new ArrayList<>(); public int curDeep; Public void addFilter(FileFilter countFilter) {mfilter.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 ()) {// if the node is a file 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++; curDeep++; scan(child); } else { fileCount++; Length += f.length(); } } curDeep--; } /** * Initialize Filer data ** @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; // Child node collection public File File; // File path 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 + '}'; }} /** * Author: Zhang Fengjie Teilie * Time: 2019/2/13/013:14:31 * Email: [email protected] * Description: File filtering interface */ public interface FileFilter {/** * Check whether the File is filtered by the path * @param path path * @return Whether the filter */ Boolean iCanGo(File)  path); / / void filter(file file, int deep); / / void filter(file file, int deep); } /** * Author: Zhang Feng jiete Lie * Time: 2019/2/13/013:10:59 * Email: [email protected] * Description: */ public class StructureBuilder implements FileFilter {String prefix; String blank; StringBuilder sb = new StringBuilder(" directory structure :\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; } /** * writeFile structure to file * @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(" zhang Feng Jettison -- modified to "+ time + "\n"); fw.write(sb.toString()); } catch (IOException e) { e.printStackTrace(); } finally { try { if (fw ! = null) { fw.close(); } } catch (IOException e) { e.printStackTrace(); }}}} / / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- the following is a plug-in part -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- the class ListDirPlugin implements Plugin<Project> {// This interface defines an apply() method, where we can manipulate the Project, // add tasks to it, define additional properties, etc. Void the apply (Project Project) {/ / load the Extension Project. The extensions. Create (" listDir." MkDirPluginPluginExtension) / / use the Extension configuration information for the project. The 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 {/ / expand parameter String path = '}Copy the code

Postscript: Jie wen standard

1. Growth record and Errata of this paper
Program source code The date of The appendix
V0.1– The 2018-2-13 There is no

Publish name: miscellaneous – miscellaneous talk initiated from File operations [-file -]

Czech text links: www.jianshu.com/u/e4e52c116…

2. More about me
Pen name QQ WeChat
Zhang Feng Jie te Li 1981462002 zdl1994328

My github: github.com/toly1994328

I’m Jane books: www.jianshu.com/u/e4e52c116… My nuggets: juejin.cn/user/149189… Personal website: www.toly1994.com

3. The statement

1—- This article is originally written by Zhang Fengjie, please note if reproduced

2—- welcome the majority of programming enthusiasts to communicate with each other 3—- personal ability is limited, if there is something wrong welcome to criticize and testify, must be humble to correct 4—- see here, I thank you here for your love and support