目录
3、ResourceFileTree读取的文件目录、文件实体类
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));
}
}