You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

基于os.walk的目录文件变更追踪工具优化技术问询

解决方案:实现文件夹变更追踪与标记

我来帮你搞定这个变更追踪的需求!你的思路用日志文件对比是完全正确的,只是可能在元数据记录对比逻辑上没处理到位。下面是完整的实现方案,包含代码和详细说明:

核心思路

  1. 记录历史状态:每次运行时,把当前文件夹所有文件/子文件夹的路径、类型(文件/文件夹)、最后修改时间戳保存到一个JSON日志文件中
  2. 对比当前与历史状态:下次运行时,读取历史日志,和当前扫描的状态做对比
  3. 标记变更内容:用红色终端输出标记新增的文件/文件夹修改过的文件(文件夹修改时间变化也标记)

完整实现代码

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)

关键细节说明

  1. 日志存储格式:用JSON保存历史记录,每条记录包含路径、类型和修改时间戳,比纯文本更容易解析和对比
  2. 时间戳对比:用时间戳而不是字符串对比,避免不同系统时间格式的问题,同时留1秒误差,防止系统时间精度导致的误判
  3. 终端颜色输出:使用ANSI转义码实现红色标记,大部分Windows、Linux、Mac终端都支持(Windows如果不显示颜色,可以先运行os.system('color')启用)
  4. 异常处理:处理扫描过程中文件被删除的情况,避免脚本崩溃
  5. 可选功能:代码中包含了删除项的检测,如果不需要可以注释掉这部分逻辑

输出效果示例

=== 扫描路径: 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', My Text 3.txt]

C:\Users\J\MyFolder\1.My Pic
  This Folder is empty :(

内容的提问来源于stack exchange,提问作者j.py

火山引擎 最新活动