如何用Python os.walk生成嵌套JSON格式的文件重命名日志
实现方案与优化建议
核心实现逻辑
要解决os.walk()平级遍历与嵌套JSON结构的匹配问题,核心是用路径-节点映射字典跟踪每个目录对应的JSON节点,快速定位父节点并构建层级:
- 初始化根节点:创建根目录对应的JSON节点,存入路径-节点映射字典。
- 遍历并关联节点:
- 遍历
os.walk()返回的每个目录路径,若该路径不在映射中,则拆分路径找到父节点,创建当前目录节点并加入父节点的children列表,同时更新映射字典。 - 处理当前目录下的文件,记录重命名前后的信息到当前节点的
files字段。
- 遍历
- 清理空字段:遍历生成的JSON结构,移除无内容的
children字段(或保留空列表,按需选择)。
代码示例
import os import json from datetime import datetime # 模拟用户定义的重命名规则(根据实际需求替换) class RenameRules: def get_dir_new_name(self, dir_path): # 示例:给目录名加前缀"renamed_" dir_name = os.path.basename(dir_path) return os.path.join(os.path.dirname(dir_path), f"renamed_{dir_name}") def get_file_new_name(self, file_path): # 示例:给文件名加前缀"renamed_" file_name = os.path.basename(file_path) return f"renamed_{file_name}" def generate_rename_log(root_dir): rules = RenameRules() # 路径到JSON节点的映射,快速查找父节点 path_node_map = {} # 初始化根节点 root_node = { "original_path": root_dir, "renamed_path": rules.get_dir_new_name(root_dir), "files": [], "children": [], "operation_time": datetime.now().isoformat() } path_node_map[root_dir] = root_node # 遍历目录结构(topdown=True,方便修改子目录名) for dirpath, dirnames, filenames in os.walk(root_dir, topdown=True): current_node = path_node_map.get(dirpath) if not current_node: # 找不到当前节点,说明是子目录,先找父节点 parent_path = os.path.dirname(dirpath) parent_node = path_node_map[parent_path] # 创建当前目录节点 current_node = { "original_path": dirpath, "renamed_path": rules.get_dir_new_name(dirpath), "files": [], "children": [] } parent_node["children"].append(current_node) path_node_map[dirpath] = current_node # 处理文件重命名并记录 for filename in filenames: original_file = os.path.join(dirpath, filename) new_filename = rules.get_file_new_name(original_file) renamed_file = os.path.join(current_node["renamed_path"], new_filename) # 执行重命名(实际项目中可增加异常捕获,记录状态) try: os.rename(original_file, renamed_file) current_node["files"].append({ "original_name": filename, "original_path": original_file, "renamed_name": new_filename, "renamed_path": renamed_file, "status": "success" }) except Exception as e: current_node["files"].append({ "original_name": filename, "original_path": original_file, "status": "failed", "error_message": str(e) }) # 修改dirnames,让os.walk后续遍历重命名后的子目录 for i, dirname in enumerate(dirnames): original_subdir = os.path.join(dirpath, dirname) new_subdir_name = os.path.basename(rules.get_dir_new_name(original_subdir)) dirnames[i] = new_subdir_name # 重命名子目录 os.rename(original_subdir, os.path.join(dirpath, new_subdir_name)) # 清理空的children字段(若需要保留空列表,可跳过此步骤) def clean_empty_children(node): if not node.get("children"): node.pop("children", None) else: for child in node["children"]: clean_empty_children(child) # 若目录下无文件,也可移除files字段 if not node.get("files"): node.pop("files", None) return node cleaned_root = clean_empty_children(root_node) return cleaned_root # 生成日志并保存 if __name__ == "__main__": target_dir = "/path/to/your/target/dir" rename_log = generate_rename_log(target_dir) with open("rename_operation_log.json", "w", encoding="utf-8") as f: json.dump(rename_log, f, indent=2, ensure_ascii=False)
JSON结构优化建议
- 统一字段风格:保持字段命名一致(如全下划线
original_path或驼峰originalPath),避免混用。 - 增加元数据:在顶层节点加入操作时间、规则版本、根目录等信息,提升日志的可追溯性。
- 完善状态记录:给每个文件/目录的重命名操作增加
status(success/failed)和error_message字段,方便排查异常。 - 按需精简字段:
- 若无子目录则移除
children字段(或保留空列表,根据日志解析需求选择); - 若目录下无文件,可移除
files字段,减少冗余。
- 若无子目录则移除
- 简化目录信息:若
original_path已包含目录名,可去掉单独的dir_name字段,避免重复。
内容的提问来源于stack exchange,提问作者dblinkhorn
相关产品推荐
相关产品推荐

