用Java写一个输出纯文本的目录树
程序员文章站
2022-06-13 22:45:51
...
之前在用HUI的模板时看他的目录结构时他给了一个纯文本格式的目录结构,像这样.
以前不是这样的,老版本好看多了,反正搞个截图吧.后面自己搞一些项目的目录结构时,都是手搓控制格式.后面没事自己整了个目录扫描工具类,后面再看目录的结构什么的就一目了然了.
直接上自己写的一个目录扫描工具类吧:
package com.gxlm.temp.tools;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.gxlm.core.util.CollectionUtil;
import org.gxlm.core.util.FileUtil;
import org.gxlm.core.util.IOUtil;
import org.gxlm.core.util.Resource;
import org.gxlm.core.util.StringUtil;
/**
* Description 类描述: <br/>
* 目录树
*
* @version 创建时间:2019年10月23日 上午10:10:16
*/
public class DirecTree {
// 空白分隔符
private static final String BLANK_SPLIT = " ";
// 竖线分隔符
private static final String VERTICAL_BLANK_SPLIT = "│ ";
// 节点符
private static final String NODE = "├──";
// 文件图标
private static final String FILE_ICON = "▶ ○ ";
// 非空目录图标
private static final String DIREC_ICON = "▼ ◇ ";
// 空目录图标
private static final String EMPTY_DIREC_ICON = "▶ ◇ ";
// 文件节点
private static String FILE_NODE = NODE;
// 非空目录节点
private static String DIREC_NODE = NODE;
// 空目录节点
private static String EMPTY_DIREC_NODE = NODE;
// 扫描目录
private File direc;
/**
* 目录树
*
* @version 日期:2019年10月25日
* @param direc 扫描目录
*/
public DirecTree(String direc) {
this(direc, false);
}
/**
* 目录树
*
* @version 日期:2019年10月25日
* @param direc 扫描目录
* @param showIcon 是否显示区分文件目录图标
*/
public DirecTree(String direc, boolean showIcon) {
this(new File(direc), showIcon);
}
/**
* 目录树
*
* @version 日期:2019年10月25日
* @param direc 扫描目录
*/
public DirecTree(File direc) {
this(direc, false);
}
/**
* 目录树
*
* @version 日期:2019年10月25日
* @param direc 扫描目录
* @param showIcon 是否显示区分文件目录图标
*/
public DirecTree(File direc, boolean showIcon) {
this.direc = direc;
if (showIcon) {
FILE_NODE = NODE + FILE_ICON;
DIREC_NODE = NODE + DIREC_ICON;
EMPTY_DIREC_NODE = NODE + EMPTY_DIREC_ICON;
}
}
/**
* 绘制目录树
*
* @version 日期:2019年10月25日
*/
public void draw() {
drawDirecTree(direc, "", false, 1, null, null);
}
/**
* 绘制目录树
*
* @version 日期:2019年10月25日
* @param outFile 绘制树保存文件
* @param limitLevel 限制绘制深度
* @param likeEclipse 按eclipse的包结构绘制目录树(目录下只有一个子目录,子目录不占用一个分支)
*/
public void draw(File outFile, Integer limitLevel, boolean likeEclipse) {
StringBuilder builder = outFile == null ? null : new StringBuilder();
if (likeEclipse) {
File parentFile = direc.getParentFile();
if (parentFile == null)// 根目录
drawDirecTreeLikeEclipse(direc, null, "", false, 1, limitLevel, builder);
else
drawDirecTreeLikeEclipse(direc, parentFile.getAbsolutePath(), "", false, 1, limitLevel, builder);
} else {
drawDirecTree(direc, "", false, 1, limitLevel, builder);
}
if (builder != null)
IOUtil.writeText(builder.toString(), outFile, "UTF-8", true);
}
/**
* 绘制目录树-以eclipse的package视图风格显示目录文件
*
* @version 日期:2019年3月19日
* @param file
* @param basePath
* @param prefix 节点前缀
* @param hasNext file是否有兄弟file
* @param level 目录树深度
* @param limitLevel 限定显示目录树深度上限
* @param builder
*/
private void drawDirecTreeLikeEclipse(File file, String basePath, String prefix, boolean hasNext, int level,
Integer limitLevel, StringBuilder builder) {
if (limitLevel != null && level > limitLevel.intValue())
return;
// 根目录路径以"\"字符结尾,而普通目录不以"\"字符结尾,这里统一下都不以"\"字符
if (StringUtil.isNotBlank(basePath) && basePath.lastIndexOf(File.separatorChar) == basePath.length() - 1)
basePath = basePath.substring(0, basePath.length() - 1);
// 文件
if (file.isFile()) {
String nodeInfo = prefix + FILE_NODE + file.getName() + "(" + FileUtil.formatFileSize(file.length()) + ")";
if (builder == null)
System.out.println(nodeInfo);
else
builder.append(nodeInfo).append("\r\n");
return;
}
File[] fileArr = file.listFiles();
// 空目录
if (CollectionUtil.isEmpty(fileArr)) {
String nodeInfo = prefix + EMPTY_DIREC_NODE;
if (StringUtil.isBlank(basePath))
nodeInfo += file.getAbsolutePath().replace(File.separator, file.getParentFile() == null? "": ".");
else
nodeInfo += file.getAbsolutePath().substring(basePath.length() + 1).replace(File.separatorChar, '.');
if (builder == null)
System.out.println(nodeInfo);
else
builder.append(nodeInfo).append("\r\n");
return;
}
// 目录下有且仅有一个子目录
if (fileArr.length == 1 && fileArr[0].isDirectory()) {
File f = fileArr[0];
while (true) {
File[] tempFileArr = f.listFiles();
if (CollectionUtil.isEmpty(tempFileArr) || tempFileArr.length > 1 || tempFileArr[0].isFile())
break;
f = tempFileArr[0];
}
drawDirecTreeLikeEclipse(f, basePath, prefix, hasNext, level + 1, limitLevel, builder);
return;
}
// 打印当前目录
String nodeInfo = prefix + DIREC_NODE;
if (StringUtil.isBlank(basePath))
nodeInfo += file.getAbsolutePath().replace(File.separator, file.getParentFile() == null? "": ".");
else
nodeInfo += file.getAbsolutePath().substring(basePath.length() + 1).replace(File.separatorChar, '.');
if (builder == null)
System.out.println(nodeInfo);
else
builder.append(nodeInfo).append("\r\n");
// 子目录及文件
String p = prefix + (hasNext ? VERTICAL_BLANK_SPLIT : BLANK_SPLIT);
List<File> direcList = new ArrayList<File>();
for (File item : fileArr) {
if (item.isFile())
drawDirecTreeLikeEclipse(item, file.getAbsolutePath(), p, false, level + 1, limitLevel, builder);
else
direcList.add(item);
}
if (CollectionUtil.isEmpty(direcList))
return;
for (int i = 0; i < direcList.size(); i++)
drawDirecTreeLikeEclipse(direcList.get(i), file.getAbsolutePath(), p, i != direcList.size() - 1, level + 1,
limitLevel, builder);
}
/**
* 绘制目录树-每个目录均占用一个位置(即只有一个子目录的也要展开)
*
* @version 日期:2019年10月23日
* @param file
* @param prefix 节点前缀
* @param hasNext file是否有兄弟file
* @param level 目录树深度
* @param limitLevel 限定显示目录树深度上限
* @param builder
*/
private void drawDirecTree(File file, String prefix, boolean hasNext, int level, Integer limitLevel,
StringBuilder builder) {
if (limitLevel != null && level > limitLevel.intValue())
return;
// 文件
if (file.isFile()) {
String nodeInfo = prefix + FILE_NODE + file.getName() + "(" + FileUtil.formatFileSize(file.length()) + ")";
if (builder == null)
System.out.println(nodeInfo);
else
builder.append(nodeInfo).append("\r\n");
return;
}
File[] fileArr = file.listFiles();
// 空目录
if (CollectionUtil.isEmpty(fileArr)) {
String nodeInfo = prefix + EMPTY_DIREC_NODE + (file.getParentFile() == null? file.getPath().replace(File.separator, ""): file.getName());
if (builder == null)
System.out.println(nodeInfo);
else
builder.append(nodeInfo).append("\r\n");
return;
}
// 打印当前目录
String nodeInfo = prefix + DIREC_NODE + (file.getParentFile() == null? file.getPath().replace(File.separator, ""): file.getName());
if (builder == null)
System.out.println(nodeInfo);
else
builder.append(nodeInfo).append("\r\n");
// 递归打印子目录及文件
String p = prefix + (hasNext ? VERTICAL_BLANK_SPLIT : BLANK_SPLIT);
List<File> direcList = new ArrayList<File>();
for (File item : fileArr) {
if (item.isFile())
drawDirecTree(item, p, false, level + 1, limitLevel, builder);
else
direcList.add(item);
}
if (CollectionUtil.isEmpty(direcList))
return;
for (int i = 0; i < direcList.size(); i++)
drawDirecTree(direcList.get(i), p, i != direcList.size() - 1, level + 1, limitLevel, builder);
}
/**
* 测试绘制目树
*
* @version 日期:2019年10月23日
* @param args
*/
public static void main(String[] args) {
// 目录树,所有目录均展开,不限定目录深度,结果输出到控制台上
//new DirecStruct("E:\\Recently").draw();
// 目录树,像eclipse展示包结构一样展示目录树,不限定目录深度,结果输出到控制台上
// new DirecStruct("E:\\Recently").draw(null, null, true);
// 目录树,像eclipse展示包结构一样展示目录树,不限定目录深度,结果输出到桌面上
new DirecTree("F:\\").draw(new File(Resource.getDesktopPath() + File.separatorChar + "西数-F盘.txt"), null, false);
}
}
生成效果:
FileUtil.formatFileSize(file.length())是格式化文件大小单位,这里也给下
public static String formatFileSize(long fileSize) {
if (fileSize < 1024)
return fileSize + "Byte";
else if (fileSize < 1024 * 1024)
return ((long) (fileSize / 1024.0 * 100)) / 100.0 + "KB";
else if (fileSize < 1024 * 1024 * 1024)
return ((long) (fileSize / 1048576.0 * 100)) / 100.0 + "MB";
else
return ((long) (fileSize / 1073741824.0 * 100)) / 100.0 + "GB";
}