基于os.walk的目录文件变更追踪工具优化技术问询
解决方案:实现文件夹变更追踪与标记
我来帮你搞定这个变更追踪的需求!你的思路用日志文件对比是完全正确的,只是可能在元数据记录和对比逻辑上没处理到位。下面是完整的实现方案,包含代码和详细说明:
核心思路
- 记录历史状态:每次运行时,把当前文件夹所有文件/子文件夹的路径、类型(文件/文件夹)、最后修改时间戳保存到一个JSON日志文件中
- 对比当前与历史状态:下次运行时,读取历史日志,和当前扫描的状态做对比
- 标记变更内容:用红色终端输出标记新增的文件/文件夹和修改过的文件(文件夹修改时间变化也标记)
完整实现代码
import os import json from datetime import datetime # 日志文件路径,建议放在和脚本同目录下 HISTORY_LOG_PATH = "folder_scan_history.json" def load_history_log(): """加载上次扫描的历史记录""" if not os.path.exists(HISTORY_LOG_PATH): return {} try: with open(HISTORY_LOG_PATH, 'r', encoding='utf-8') as f: return json.load(f) except json.JSONDecodeError: # 如果日志文件损坏,返回空字典 return {} def save_history_log(current_state): """保存当前扫描的状态到日志文件""" with open(HISTORY_LOG_PATH, 'w', encoding='utf-8') as f: json.dump(current_state, f, indent=2, ensure_ascii=False) def scan_current_state(root_path): """扫描指定路径下所有文件和文件夹的元数据""" current_state = {} for root, dirs, files in os.walk(root_path): # 记录当前目录 dir_mtime = os.path.getmtime(root) current_state[root] = { "type": "dir", "mtime": dir_mtime } # 记录当前目录下的文件 for file in files: file_path = os.path.join(root, file) try: file_mtime = os.path.getmtime(file_path) current_state[file_path] = { "type": "file", "mtime": file_mtime } except FileNotFoundError: # 处理扫描过程中文件被删除的情况 continue return current_state def print_colored(text, color="red"): """带颜色的终端输出,默认红色""" color_codes = { "red": "\033[91m", "reset": "\033[0m" } return f"{color_codes[color]}{text}{color_codes['reset']}" def compare_and_show_changes(root_path, history_state, current_state): """对比历史和当前状态,输出变更内容""" print(f"=== 扫描路径: {root_path} ===") print(f"=== 扫描时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')} ===") print("\n--- 变更内容 ---") # 遍历当前所有项,检查新增或修改 for path, meta in current_state.items(): # 判断是否是新增项 if path not in history_state: item_type = "文件夹" if meta["type"] == "dir" else "文件" print(f"{print_colored('[新增]')} {item_type}: {path}") continue # 判断是否是修改项(时间戳变化) history_mtime = history_state[path]["mtime"] if abs(meta["mtime"] - history_mtime) > 1: # 留1秒误差,避免系统时间精度问题 item_type = "文件夹" if meta["type"] == "dir" else "文件" print(f"{print_colored('[修改]')} {item_type}: {path}") # 可选:检查被删除的项(如果需要的话) deleted_items = [path for path in history_state if path not in current_state] if deleted_items: print("\n--- 删除内容 ---") for path in deleted_items: item_type = "文件夹" if history_state[path]["type"] == "dir" else "文件" print(f"{print_colored('[删除]', 'red')} {item_type}: {path}") print("\n--- 完整目录结构 ---") # 输出完整结构,标记变更项 for root, dirs, files in os.walk(root_path): # 处理当前目录的显示 dir_display = root if root in current_state and (root not in history_state or abs(current_state[root]["mtime"] - history_state.get(root, {}).get("mtime", 0)) > 1): dir_display = print_colored(dir_display) print(dir_display) # 处理文件的显示 file_list = [] for file in files: file_path = os.path.join(root, file) file_display = file if file_path in current_state and (file_path not in history_state or abs(current_state[file_path]["mtime"] - history_state.get(file_path, {}).get("mtime", 0)) > 1): file_display = print_colored(file_display) file_list.append(file_display) if file_list: print(f" 文件列表: {file_list}") else: print(f" {print_colored('This Folder is empty :(')}") print() if __name__ == "__main__": # 替换成你要扫描的路径 TARGET_PATH = r'C:\Users\J\MyFolder' # 加载历史记录 history = load_history_log() # 扫描当前状态 current = scan_current_state(TARGET_PATH) # 对比并显示变更 compare_and_show_changes(TARGET_PATH, history, current) # 保存当前状态到历史日志 save_history_log(current)
关键细节说明
- 日志存储格式:用JSON保存历史记录,每条记录包含路径、类型和修改时间戳,比纯文本更容易解析和对比
- 时间戳对比:用时间戳而不是字符串对比,避免不同系统时间格式的问题,同时留1秒误差,防止系统时间精度导致的误判
- 终端颜色输出:使用ANSI转义码实现红色标记,大部分Windows、Linux、Mac终端都支持(Windows如果不显示颜色,可以先运行
os.system('color')启用) - 异常处理:处理扫描过程中文件被删除的情况,避免脚本崩溃
- 可选功能:代码中包含了删除项的检测,如果不需要可以注释掉这部分逻辑
输出效果示例
=== 扫描路径: C:\Users\J\MyFolder === === 扫描时间: 2024-05-20 14:30:00 === --- 变更内容 --- [新增] 文件: C:\Users\J\MyFolder\Recored\My Text 3.txt [修改] 文件夹: C:\Users\J\MyFolder\1.This folder --- 完整目录结构 --- C:\Users\J\MyFolder 文件列表: [] C:\Users\J\MyFolder\1.This folder 文件列表: ['My Text 1.txt', 'My Text 2.txt'] C:\Users\J\MyFolder\Recored 文件列表: ['My Text 1.txt', 'My Text 2.txt', [91mMy Text 3.txt[0m] C:\Users\J\MyFolder\1.My Pic [91mThis Folder is empty :([0m
内容的提问来源于stack exchange,提问作者j.py




