欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

用Java写一个输出纯文本的目录树

程序员文章站 2022-06-13 22:45:51
...

之前在用HUI的模板时看他的目录结构时他给了一个纯文本格式的目录结构,像这样.

用Java写一个输出纯文本的目录树

以前不是这样的,老版本好看多了,反正搞个截图吧.后面自己搞一些项目的目录结构时,都是手搓控制格式.后面没事自己整了个目录扫描工具类,后面再看目录的结构什么的就一目了然了.

直接上自己写的一个目录扫描工具类吧:

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);
    }

}

生成效果:

用Java写一个输出纯文本的目录树

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";
	}