Java读取指定目录,返回树形结构数据

目录

1、添加依赖

2、FileMessage树形结构实体类

3、ResourceFileTree读取的文件目录、文件实体类

4、读取目录文件工具类

 5、TreeUtil将普通list数据转换为树形数据结构

6、测试调用输出数据结构

7、第二种方法直接读取返回树形结构


1、添加依赖

<dependency>
	<groupId>com.alibaba</groupId>
	<artifactId>fastjson</artifactId>
	<version>1.2.3</version>
</dependency>
<dependencies>
	<dependency>
		<groupId>org.projectlombok</groupId>
		<artifactId>lombok</artifactId>
	</dependency>
</dependencies>

2、FileMessage树形结构实体类

package com.shucha.deveiface.biz.model;

import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import java.util.List;

/**
 * @author tqf
 * @Description
 * @Version 1.0
 * @since 2022-04-19 17:01
 */
@Data
public class FileMessage {

    @ApiModelProperty(value = "主键id")
    private Integer id;

    @ApiModelProperty(value = "父id")
    private Integer parentId;

    /**
     * 类型 0-文件夹,1-文件
     */
    private Integer type;

    /**
     * 文件名称
     */
    private String fileName;

    /**
     * 文件路径
     */
    private String filePath;
    /**
     * 文件大小
     */
    private Long fileSize;
    /**
     * 文件类型
     */
    private String fileType;
    /**
     * 子目录文件列表
     */
    private List<FileMessage> chindren;

}

3、ResourceFileTree读取的文件目录、文件实体类

package com.shucha.deveiface.biz.model;

/**
 * @author tqf
 * @Description
 * @Version 1.0
 * @since 2022-04-20 14:57
 */
import lombok.Data;

@Data
public class ResourceFileTree {
    /**
     *
     */
    private int treeId;
    /**
     * 父ID
     */
    private int pid;
    /**
     * 资源ID
     */
    private String resourcesId;
    /**
     * 文件名称、目录名
     */
    private String fileName;
    /**
     * 文件路径
     */
    private String filePath;
    /**
     * 文件大小
     */
    private Long size;

    /**
     * true-文件,false-目录
     */
    private Boolean isFile;
    private boolean expanded = false;
}

4、读取目录文件工具类

package com.shucha.deveiface.biz.utils;

/**
 * @author tqf
 * @Description
 * @Version 1.0
 * @since 2022-04-20 14:57
 */
import com.alibaba.fastjson.JSONArray;
import com.shucha.deveiface.biz.model.FileMessage;
import com.shucha.deveiface.biz.model.ResourceFileTree;
import org.apache.commons.lang3.StringUtils;

import java.io.File;
import java.util.*;

public class FileTree {
    //用于储存找到的每一个文件
    List<ResourceFileTree> node=new LinkedList();

    /**
     * 读取文件目录返回树形结构
     * @param path 文件路径
     * @param id 每条记录的id
     * @param pid 父id
     * @param resourcesId 数据资源的id
     * @param fileFilter 过滤掉某个命名的文件
     * @return
     */
    private  List<ResourceFileTree> getFile(String path, int id, int pid, String resourcesId,String fileFilter) {
        File file = new File(path);
        if(file.exists()) {
            File[] array = file.listFiles();
            List fileList = Arrays.asList(array);
            //对读到的本地文件夹进行排序
            Collections.sort(fileList, new Comparator<File>() {
                @Override
                public int compare(File o1, File o2) {
                    if (o1.isDirectory() && o2.isFile()){
                        return -1;
                    }
                    if (o1.isFile() && o2.isDirectory()){
                        return 1;
                    }
                    return o1.getName().compareTo(o2.getName());
                }
            });

            for (int i = 0; i < array.length; i++) {
                ResourceFileTree resourceFileTree = new ResourceFileTree();
                //过滤文件
                if(StringUtils.isNotBlank(fileFilter) && fileFilter.equals(array[i].getName())){
                    continue;
                }
                resourceFileTree.setResourcesId(resourcesId);
                resourceFileTree.setPid(pid);
                resourceFileTree.setTreeId(id);
                resourceFileTree.setFilePath(array[i].getPath());
                resourceFileTree.setFileName(array[i].getName());
                resourceFileTree.setIsFile(array[i].isFile());
                //判断是否为文件夹,是的话进行递归
                if (array[i].isDirectory()) {
                    node.add(resourceFileTree);
                    //进行递归,此时的pid为上一级的id
                    getFile(array[i].getPath(), id * 10 + 1 + i, id,resourcesId,fileFilter);
                    id++;
                } else {
                    resourceFileTree.setSize(array[i].length());
                    node.add(resourceFileTree);
                    id++;
                }
            }
        }
        return node;
    }

    public List<ResourceFileTree> getFileTree(String resourcesId, String path,String fileFilter) {
        node.removeAll(node);
        FileTree counter = new FileTree();
        int level=0;
        List<ResourceFileTree> file = counter.getFile(path, 1, level,resourcesId,fileFilter);
        return file;
    }
}

 5、TreeUtil将普通list数据转换为树形数据结构

package com.shucha.deveiface.biz.utils;

import org.springframework.util.StringUtils;

import javax.validation.constraints.NotNull;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

/**
 * list -> tree
 * 将普通list数据转换为树形数据结构
 */
public class TreeUtil {

    /**
     * 集合转树结构
     *
     * @param list  目标集合
     * @param clazz 集合元素类型
     * @return 转换后的树形结构
     */
    public static <T> List<T> toTree(@NotNull List<T> list, @NotNull Class<T> clazz) {
        return toTree(list, null, null, null, clazz);
    }

    /**
     * 集合转树结构
     *
     * @param list     目标集合列表
     * @param id       节点编号字段名称
     * @param parent   父节点编号字段名称
     * @param children 子节点集合属性名称
     * @param clazz    集合元素类型
     * @return 转换后的树形结构
     */
    public static <T> List<T> toTree(@NotNull List<T> list, String id, String parent, String children, @NotNull Class<T> clazz) {
        try {
            // 如果目标集合为空,直接返回一个空树
            if (list == null || list.isEmpty()) return null;
            // 如果被依赖字段名称为空则默认为id
            if (StringUtils.isEmpty(id)) id = "id";
            // 如果依赖字段为空则默认为parent
            if (StringUtils.isEmpty(parent)) parent = "pid";
            // 如果子节点集合属性名称为空则默认为children
            if (StringUtils.isEmpty(children)) children = "children";

            // 初始化根节点集合, 支持 Set 和 List
            List<T> roots = new ArrayList<>();

            // 获取 id 字段, 从当前对象或其父类
            Field idField;
            try {
                idField = clazz.getDeclaredField(id);
            } catch (NoSuchFieldException e1) {
                idField = clazz.getSuperclass().getDeclaredField(id);
            }

            // 获取 parentId 字段, 从当前对象或其父类
            Field parentField;
            try {
                parentField = clazz.getDeclaredField(parent);
            } catch (NoSuchFieldException e1) {
                parentField = clazz.getSuperclass().getDeclaredField(parent);
            }

            // 获取 children 字段, 从当前对象或其父类
            Field childrenField;
            try {
                childrenField = clazz.getDeclaredField(children);
            } catch (NoSuchFieldException e1) {
                childrenField = clazz.getSuperclass().getDeclaredField(children);
            }

            // 设置为可访问
            idField.setAccessible(true);
            parentField.setAccessible(true);
            childrenField.setAccessible(true);

            // 找出所有的根节点
            for (T c : list) {
                Object parentId = parentField.get(c);
                if (isRootNode(parentId)) {
                    roots.add(c);
                }
            }

            // 从目标集合移除所有根节点
            list.removeAll(roots);

            // 遍历根节点, 依次添加子节点
            for (T root : roots) {
                addChild(root, list, idField, parentField, childrenField);
            }

            // 关闭可访问
            idField.setAccessible(false);
            parentField.setAccessible(false);
            childrenField.setAccessible(false);

            return roots;
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 为目标节点添加孩子节点
     *
     * @param node          目标节点
     * @param list          目标集合
     * @param idField       ID 字段
     * @param parentField   父节点字段
     * @param childrenField 字节点字段
     */
    private static <T> void addChild(@NotNull T node, @NotNull List<T> list, @NotNull Field idField, @NotNull Field parentField, @NotNull Field childrenField) throws IllegalAccessException {
        Object id = idField.get(node);
        List<T> children = (List<T>) childrenField.get(node);
        // 如果子节点的集合为 null, 初始化孩子集合
        if (children == null) {
            children = new ArrayList<>();
        }

        for (T t : list) {
            Object o = parentField.get(t);
            if (id.equals(o)) {
                // 将当前节点添加到目标节点的孩子节点
                children.add(t);
                // 重设目标节点的孩子节点集合,这里必须重设,因为如果目标节点的孩子节点是null的话,这样是没有地址的,就会造成数据丢失,所以必须重设,如果目标节点所在类的孩子节点初始化为一个空集合,而不是null,则可以不需要这一步,因为java一切皆指针
                childrenField.set(node, children);
                // 递归添加孩子节点
                addChild(t, list, idField, parentField, childrenField);
            }
        }
    }

    /**
     * 判断是否是根节点, 判断方式为: 父节点编号为空或为 0, 则认为是根节点. 此处的判断应根据自己的业务数据而定.
     *
     * @param parentId 父节点编号
     * @return 是否是根节点
     */
    private static boolean isRootNode(Object parentId) {
        boolean flag = false;
        if (parentId == null) {
            flag = true;
        } else if (parentId instanceof String && (StringUtils.isEmpty(parentId) || parentId.equals("0"))) {
            flag = true;
        } else if (parentId instanceof Integer && Integer.valueOf(0).equals(parentId)) {
            flag = true;
        } else if (parentId instanceof Long && Long.valueOf("0").equals(parentId)) {
            flag = true;
        }
        return flag;
    }

}

6、测试调用输出数据结构

 public static void main(String[] args) {
        FileTree counter = new FileTree();
        // 返回所有文件目录和文件 但是是list结构不是树形结构
        List<ResourceFileTree> fileResourceFileTree = counter.getFileTree("5asd5as6d8asdas4dqw873e4", "D:\\fileTest","");
        // 下面处理为树形结构
        List<FileMessage> list = new ArrayList<>();
        for (ResourceFileTree data : fileResourceFileTree){
            FileMessage message = new FileMessage();
            message.setId(data.getTreeId());
            message.setParentId(data.getPid());
            message.setFileSize(data.getSize());
            message.setFileName(data.getFileName());
            message.setFilePath(data.getFilePath());
            message.setType(data.getIsFile() ? 1: 0);
            list.add(message);
        }
        List<FileMessage> powerListDTOSs = TreeUtil.toTree(list, "id", "parentId", "chindren", FileMessage.class);
        System.out.println(JSONArray.toJSON(powerListDTOSs));
    }

 整理之后的数据:

[{
	"fileName": "QQ202204200927_OCR",
	"chindren": [{
		"fileName": "pic.jpg",
		"fileSize": 57840,
		"filePath": "D:\\fileTest\\QQ202204200927_OCR\\pic.jpg",
		"id": 11,
		"type": 1,
		"parentId": 1
	}, {
		"fileName": "result.txt",
		"fileSize": 969,
		"filePath": "D:\\fileTest\\QQ202204200927_OCR\\result.txt",
		"id": 12,
		"type": 1,
		"parentId": 1
	}],
	"filePath": "D:\\fileTest\\QQ202204200927_OCR",
	"id": 1,
	"type": 0,
	"parentId": 0
}, {
	"fileName": "tortoisegit-languagepack",
	"chindren": [{
		"fileName": "TortoiseGit-LanguagePack-2.11.0.0-32bit-zh_CN.msi",
		"fileSize": 2846720,
		"filePath": "D:\\fileTest\\tortoisegit-languagepack\\TortoiseGit-LanguagePack-2.11.0.0-32bit-zh_CN.msi",
		"id": 22,
		"type": 1,
		"parentId": 2
	}, {
		"fileName": "TortoiseGit-LanguagePack-2.11.0.0-64bit-zh_CN.msi",
		"fileSize": 4354048,
		"filePath": "D:\\fileTest\\tortoisegit-languagepack\\TortoiseGit-LanguagePack-2.11.0.0-64bit-zh_CN.msi",
		"id": 23,
		"type": 1,
		"parentId": 2
	}, {
		"fileName": "TortoiseGit-LanguagePack-2.13.0.0-32bit-zh_CN.msi",
		"fileSize": 2863104,
		"filePath": "D:\\fileTest\\tortoisegit-languagepack\\TortoiseGit-LanguagePack-2.13.0.0-32bit-zh_CN.msi",
		"id": 24,
		"type": 1,
		"parentId": 2
	}, {
		"fileName": "TortoiseGit-LanguagePack-2.13.0.0-64bit-zh_CN.msi",
		"fileSize": 4382720,
		"filePath": "D:\\fileTest\\tortoisegit-languagepack\\TortoiseGit-LanguagePack-2.13.0.0-64bit-zh_CN.msi",
		"id": 25,
		"type": 1,
		"parentId": 2
	}],
	"filePath": "D:\\fileTest\\tortoisegit-languagepack",
	"id": 2,
	"type": 0,
	"parentId": 0
}, {
	"fileName": "空文件夹",
	"filePath": "D:\\fileTest\\空文件夹",
	"id": 3,
	"type": 0,
	"parentId": 0
}, {
	"fileName": "第一层文件夹",
	"chindren": [{
		"fileName": "点点滴滴",
		"chindren": [{
			"fileName": "新建 DOCX 文档.docx",
			"fileSize": 0,
			"filePath": "D:\\fileTest\\第一层文件夹\\点点滴滴\\新建 DOCX 文档.docx",
			"id": 441,
			"type": 1,
			"parentId": 44
		}, {
			"fileName": "新建 XLSX 工作表.xlsx",
			"fileSize": 10131,
			"filePath": "D:\\fileTest\\第一层文件夹\\点点滴滴\\新建 XLSX 工作表.xlsx",
			"id": 442,
			"type": 1,
			"parentId": 44
		}, {
			"fileName": "新建文本文档.txt",
			"fileSize": 0,
			"filePath": "D:\\fileTest\\第一层文件夹\\点点滴滴\\新建文本文档.txt",
			"id": 443,
			"type": 1,
			"parentId": 44
		}],
		"filePath": "D:\\fileTest\\第一层文件夹\\点点滴滴",
		"id": 44,
		"type": 0,
		"parentId": 4
	}, {
		"fileName": "第二层文件夹",
		"chindren": [{
			"fileName": "第三层文件夹",
			"chindren": [{
				"fileName": "发发发.txt",
				"fileSize": 18,
				"filePath": "D:\\fileTest\\第一层文件夹\\第二层文件夹\\第三层文件夹\\发发发.txt",
				"id": 4521,
				"type": 1,
				"parentId": 452
			}, {
				"fileName": "对对对.xls",
				"fileSize": 6656,
				"filePath": "D:\\fileTest\\第一层文件夹\\第二层文件夹\\第三层文件夹\\对对对.xls",
				"id": 4522,
				"type": 1,
				"parentId": 452
			}],
			"filePath": "D:\\fileTest\\第一层文件夹\\第二层文件夹\\第三层文件夹",
			"id": 452,
			"type": 0,
			"parentId": 45
		}],
		"filePath": "D:\\fileTest\\第一层文件夹\\第二层文件夹",
		"id": 45,
		"type": 0,
		"parentId": 4
	}, {
		"fileName": "减肥减肥.txt",
		"fileSize": 0,
		"filePath": "D:\\fileTest\\第一层文件夹\\减肥减肥.txt",
		"id": 46,
		"type": 1,
		"parentId": 4
	}, {
		"fileName": "新建 PPT 演示文稿.ppt",
		"fileSize": 20992,
		"filePath": "D:\\fileTest\\第一层文件夹\\新建 PPT 演示文稿.ppt",
		"id": 47,
		"type": 1,
		"parentId": 4
	}],
	"filePath": "D:\\fileTest\\第一层文件夹",
	"id": 4,
	"type": 0,
	"parentId": 0
}, {
	"fileName": "2022.xls",
	"fileSize": 19968,
	"filePath": "D:\\fileTest\\2022.xls",
	"id": 5,
	"type": 1,
	"parentId": 0
}, {
	"fileName": "db_source_202201061627.sql",
	"fileSize": 0,
	"filePath": "D:\\fileTest\\db_source_202201061627.sql",
	"id": 6,
	"type": 1,
	"parentId": 0
}, {
	"fileName": "digital_potal_数据库设计文档生成_1.0.0.md",
	"fileSize": 181827,
	"filePath": "D:\\fileTest\\digital_potal_数据库设计文档生成_1.0.0.md",
	"id": 7,
	"type": 1,
	"parentId": 0
}, {
	"fileName": "接口调用量.jpeg",
	"fileSize": 75189,
	"filePath": "D:\\fileTest\\接口调用量.jpeg",
	"id": 8,
	"type": 1,
	"parentId": 0
}, {
	"fileName": "解密后的身份证号码.txt",
	"fileSize": 86,
	"filePath": "D:\\fileTest\\解密后的身份证号码.txt",
	"id": 9,
	"type": 1,
	"parentId": 0
}]

7、第二种方法直接读取返回树形结构

package com.shucha.deveiface.biz.utils;

/**
 * @author tqf
 * @Description
 * @Version 1.0
 * @since 2022-04-20 16:39
 */
import com.alibaba.fastjson.JSONObject;
import lombok.Data;
import org.apache.commons.compress.utils.Lists;
import org.springframework.util.CollectionUtils;

import java.io.File;
import java.util.List;

/**
 * 读取文件目录,返回树形结构数据
 */
@Data
public class FileTreeNode {

    /**
     * 文件名称
     */
    private String name;

    /**
     * 文件内容
     */
    private File file;

    /**
     * 文件大小
     */
    private Long fileSize;

    /**
     * 当前文件所属层级
     */
    private int level;

    /**
     * 类型  1:文件夹  2:文件
     */
    private int type;

    /**
     * 下级文件
     */
    private List<FileTreeNode> nextNodes;

    /**
     * 是否有下级
     */
    public boolean hasNext() {
        return nextNodes != null && nextNodes.size() > 0;
    }

    /**
     * 是不是文件夹
     */
    public boolean isDirectory() {
        return type == 1;
    }

    /**
     * 是不是文件
     */
    public boolean isFile() {
        return type == 2;
    }


    /**
     * 加载这个文件下的文件树  包括文件夹和文件
     *
     * @param file         要加载的文件
     * @param readMaxLevel 最大读多少层   该值小于1则表示有多少层读取多少层
     * @return
     */
    public static FileTreeNode readZipFile(File file, int readMaxLevel) {
        return readZipFile(file, 0, readMaxLevel);
    }

    private static FileTreeNode readZipFile(File file, int fileLevel, int readMaxLevel) {
        if (readMaxLevel > 0 && fileLevel > readMaxLevel) {
            return null;
        }

        // 取得文件目录中所有文件的File对象数组
        File[] files = file.listFiles();
        if (files == null || files.length < 1) {
            return null;
        }

        FileTreeNode fileTreeNode = new FileTreeNode();
        fileTreeNode.setFileSize(file.length());
        int i = file.getName().lastIndexOf(".");
        /*if (i >= 0) {
            fileTreeNode.setName(file.getName().substring(0, i));
        } else {
            fileTreeNode.setName(file.getName());
        }*/
        fileTreeNode.setName(file.getName());
        fileTreeNode.setFile(file);
        fileTreeNode.setLevel(fileLevel);
        if (file.isDirectory()) {
            //文件夹
            fileTreeNode.setType(1);
        } else {
            //文件
            fileTreeNode.setType(2);
        }

        if (CollectionUtils.isEmpty(fileTreeNode.getNextNodes())) {
            fileTreeNode.setNextNodes(Lists.newArrayList());
        }

        fileLevel++;
        // 遍历file数组
        for (File nextFile : files) {
            FileTreeNode nextTreeNode = new FileTreeNode();
            int x = nextFile.getName().lastIndexOf(".");
            /*if (x >= 0) {
                nextTreeNode.setName(nextFile.getName().substring(0, x));
            } else {
                nextTreeNode.setName(nextFile.getName());
            }*/
            nextTreeNode.setName(nextFile.getName());
            nextTreeNode.setFile(nextFile);
            nextTreeNode.setLevel(fileLevel);
            nextTreeNode.setFileSize(nextFile.length());
            if (nextFile.isDirectory()) {
                nextTreeNode.setType(1);
                // 递归子目录
                FileTreeNode fileTreeNode1 = readZipFile(nextFile, fileLevel, readMaxLevel);
                if (fileTreeNode1 != null) {
                    fileTreeNode.getNextNodes().add(fileTreeNode1);
                }
            } else {
                nextTreeNode.setType(2);
                fileTreeNode.getNextNodes().add(nextTreeNode);
            }
        }
        return fileTreeNode;
    }

    public static void main(String[] args) {
        FileTreeNode fileTreeNode = FileTreeNode.readZipFile(new File("D:\\fileTest"), 0);
        System.out.println(JSONObject.toJSONString(fileTreeNode));
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码奴生来只知道前进~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值