基于ID与父ID将CSV扁平目录转为树形层级并打印(Java/Python)
解决方案:扁平CSV目录结构转树形层级(含目录总大小计算)
我之前也处理过类似的扁平结构转树形的需求,这个问题的核心是用字典/哈希表快速映射节点ID和对应对象,这样能高效建立父子关系,再通过递归完成目录大小计算和层级打印。下面给你Python和Java两种实现方案,完全匹配你的需求:
Python 实现
思路
- 用类封装每个目录/文件节点,包含所有字段以及子节点列表、目录总大小属性
- 把所有节点存入ID映射字典,方便快速查找父节点
- 遍历节点建立父子关联,根节点(
parentId为空的节点)单独收集 - 递归计算目录总大小:目录大小 = 所有子文件大小 + 所有子目录的总大小
- 递归打印树形结构,按层级缩进
完整代码
class Node: def __init__(self, node_id, parent_id, name, type_, size, classification, checksum): self.id = node_id self.parent_id = parent_id self.name = name self.type = type_ # 处理空值:文件大小转整数,目录大小初始为0 self.size = int(size) if size.strip() else 0 self.classification = classification.strip() if classification else None self.checksum = checksum.strip() if checksum else None self.children = [] self.total_size = 0 # 目录的总大小,文件则等于自身size def build_tree(csv_data): id_to_node = {} root_nodes = [] # 第一步:解析所有节点,存入字典 for line in csv_data.strip().split('\n'): parts = line.strip().split(';') # 提取字段,注意处理末尾的空分隔符 node_id = int(parts[0]) parent_id = int(parts[1]) if parts[1].strip() else None name = parts[2] type_ = parts[3] size = parts[4] classification = parts[5] checksum = parts[6] node = Node(node_id, parent_id, name, type_, size, classification, checksum) id_to_node[node_id] = node # 标记根节点 if parent_id is None: root_nodes.append(node) # 第二步:建立父子关系 for node in id_to_node.values(): if node.parent_id is not None and node.parent_id in id_to_node: parent_node = id_to_node[node.parent_id] parent_node.children.append(node) # 第三步:递归计算目录总大小 def calculate_total_size(node): if node.type == 'file': node.total_size = node.size return node.size # 目录的总大小是所有子节点的总大小之和 total = 0 for child in node.children: total += calculate_total_size(child) node.total_size = total return total for root in root_nodes: calculate_total_size(root) return root_nodes def print_tree(nodes, indent=0): indent_str = ' ' * indent for node in nodes: if node.type == 'directory': print(f"{indent_str}name = {node.name}, type = Directory, size = {node.total_size}") # 递归打印子节点,缩进+1 print_tree(node.children, indent + 1) else: print(f"{indent_str}name = {node.name}, type = File, size = {node.size}, classification = {node.classification}, checksum = {node.checksum}") # 你的CSV数据 csv_content = """1;3;file1;file;10;Secret;42; 2; ;folder2;directory; ; ; ; 3;11;folder3;directory; ; ; ; 4;2;file4;file;40;Secret;42; 5;3;file5;file;50;Public;42; 6;3;file6;file;60;Secret;42; 7;3;file7;file;70;Public;42; 8;10;file8;file;80;Secret;42; 9;10;file9;file;90;Top secret;42; 10;11;folder10;directory; ; ; ; 11;2;folder11;directory; ; ; ;""" # 构建并打印树形结构 roots = build_tree(csv_content) print_tree(roots)
输出效果
运行后会输出和你预期一致的层级结构,目录显示总大小,文件显示完整属性,并且按层级缩进。
Java 实现
思路
和Python思路一致,用HashMap存储ID到节点的映射,自定义Node类,递归完成大小计算和打印。
完整代码
import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; class Node { private int id; private Integer parentId; // 用Integer存,支持null(根节点) private String name; private String type; private int size; private String classification; private String checksum; private List<Node> children; private int totalSize; public Node(int id, Integer parentId, String name, String type, int size, String classification, String checksum) { this.id = id; this.parentId = parentId; this.name = name; this.type = type; this.size = size; this.classification = classification; this.checksum = checksum; this.children = new ArrayList<>(); this.totalSize = 0; } // Getter和Setter方法 public int getId() { return id; } public Integer getParentId() { return parentId; } public String getName() { return name; } public String getType() { return type; } public int getSize() { return size; } public String getClassification() { return classification; } public String getChecksum() { return checksum; } public List<Node> getChildren() { return children; } public int getTotalSize() { return totalSize; } public void setTotalSize(int totalSize) { this.totalSize = totalSize; } } public class DirectoryTreeBuilder { public static List<Node> buildTree(String csvContent) { Map<Integer, Node> idToNode = new HashMap<>(); List<Node> rootNodes = new ArrayList<>(); // 解析CSV行 String[] lines = csvContent.trim().split("\n"); for (String line : lines) { String[] parts = line.trim().split(";"); int nodeId = Integer.parseInt(parts[0]); Integer parentId = parts[1].trim().isEmpty() ? null : Integer.parseInt(parts[1].trim()); String name = parts[2]; String type = parts[3]; int size = parts[4].trim().isEmpty() ? 0 : Integer.parseInt(parts[4].trim()); String classification = parts[5].trim().isEmpty() ? null : parts[5].trim(); String checksum = parts[6].trim().isEmpty() ? null : parts[6].trim(); Node node = new Node(nodeId, parentId, name, type, size, classification, checksum); idToNode.put(nodeId, node); if (parentId == null) { rootNodes.add(node); } } // 建立父子关系 for (Node node : idToNode.values()) { Integer parentId = node.getParentId(); if (parentId != null && idToNode.containsKey(parentId)) { Node parentNode = idToNode.get(parentId); parentNode.getChildren().add(node); } } // 计算目录总大小 calculateTotalSize(rootNodes); return rootNodes; } private static int calculateTotalSize(Node node) { if ("file".equals(node.getType())) { node.setTotalSize(node.getSize()); return node.getSize(); } int total = 0; for (Node child : node.getChildren()) { total += calculateTotalSize(child); } node.setTotalSize(total); return total; } private static void calculateTotalSize(List<Node> nodes) { for (Node node : nodes) { calculateTotalSize(node); } } public static void printTree(List<Node> nodes, int indent) { String indentStr = " ".repeat(indent); for (Node node : nodes) { if ("directory".equals(node.getType())) { System.out.printf("%sname = %s, type = Directory, size = %d%n", indentStr, node.getName(), node.getTotalSize()); printTree(node.getChildren(), indent + 1); } else { System.out.printf("%sname = %s, type = File, size = %d, classification = %s, checksum = %s%n", indentStr, node.getName(), node.getSize(), node.getClassification(), node.getChecksum()); } } } public static void main(String[] args) { String csvContent = """ 1;3;file1;file;10;Secret;42; 2; ;folder2;directory; ; ; ; 3;11;folder3;directory; ; ; ; 4;2;file4;file;40;Secret;42; 5;3;file5;file;50;Public;42; 6;3;file6;file;60;Secret;42; 7;3;file7;file;70;Public;42; 8;10;file8;file;80;Secret;42; 9;10;file9;file;90;Top secret;42; 10;11;folder10;directory; ; ; ; 11;2;folder11;directory; ; ; ;"""; List<Node> roots = buildTree(csvContent); printTree(roots, 0); } }
说明
Java版本同样会生成符合要求的树形输出,注意处理了CSV中的空值(比如空的parentId转为null作为根节点,空的size转为0),递归逻辑和Python完全对应。
内容的提问来源于stack exchange,提问作者karthikmunna
相关产品推荐
相关产品推荐

