4. 目录结构快照与差异对比

目录结构快照与差异对比 学习卡片

任务拆解:快照要记录什么

目录结构快照的核心是把“某一时刻的目录状态”序列化为可比较的数据。对每个文件,至少记录三项:相对路径、文件大小、最后修改时间(mtime)。目录本身也记录,但只记路径和类型,不参与“修改”判定。JSON 结构采用扁平字典,键为相对路径,值为对象,便于两次快照做集合运算。

快照 JSON 结构示例:{"src/main.py": {"type": "file", "size": 2048, "mtime": 1718000000.0}, "src/utils": {"type": "dir"}}

生成快照

用 os.walk 自顶向下遍历,os.path.relpath 转相对路径,os.stat 取大小与 mtime。mtime 用 st_mtime 浮点秒,避免格式化带来的精度损失。写入时用 json.dump(..., ensure_ascii=False, indent=2, sort_keys=True),保证同一目录两次生成的文件字节级可比。

import os, json, time

def snapshot(root):
    snap = {}
    for dirpath, dirnames, filenames in os.walk(root):
        for d in dirnames:
            p = os.path.join(dirpath, d)
            snap[os.path.relpath(p, root)] = {"type": "dir"}
        for f in filenames:
            p = os.path.join(dirpath, f)
            st = os.stat(p)
            snap[os.path.relpath(p, root)] = {
                "type": "file",
                "size": st.st_size,
                "mtime": st.st_mtime,
            }
    return snap

def save_snapshot(root, out_path):
    data = {"root": os.path.abspath(root), "time": time.time(), "entries": snapshot(root)}
    with open(out_path, "w", encoding="utf-8") as fp:
        json.dump(data, fp, ensure_ascii=False, indent=2, sort_keys=True)
    return data

差异对比逻辑

把两次快照的 entries 取出,用集合运算得到三类结果:新增 = 新键 − 旧键;删除 = 旧键 − 新键;修改 = 键相同但 size 或 mtime 不同。目录只参与新增/删除,不参与修改判定。

def diff(old, new):
    o, n = old["entries"], new["entries"]
    added   = sorted(set(n) - set(o))
    removed = sorted(set(o) - set(n))
    modified = []
    for k in sorted(set(o) & set(n)):
        a, b = o[k], n[k]
        if a["type"] != "file" or b["type"] != "file":
            continue
        if a["size"] != b["size"] or a["mtime"] != b["mtime"]:
            modified.append(k)
    return {"added": added, "removed": removed, "modified": modified}

结果判读与验证

验证方法:先对目录做一次快照存为 snap_a.json;手动新增一个文件、删除一个文件、修改一个文件内容(触发 mtime 变化);再生成 snap_b.json;运行 diff,检查三个列表是否与手动操作一一对应。若修改列表为空,先确认文件系统 mtime 精度是否足够(部分系统为秒级,快速连续写入可能不触发变化)。

mtime 精度不足时,可改用 st_mtime_ns 纳秒字段,或对文件内容做哈希(如 hashlib.sha1)作为补充判据。
目录快照与差异对比数据流 目录树 root/ src/ main.py utils.py docs/ readme.md data/ log.txt os.walk 快照 A snap_a.json main.py 2048B utils.py 1024B readme.md 512B log.txt 256B (时间点 T1) 快照 B snap_b.json main.py 3072B readme.md 512B new.txt 128B (时间点 T2) 读取 读取 diff() 集合运算 new − old old − new size/mtime 比对 目录跳过修改 输出三列表 added/removed /modified 差异结果 新增 new.txt +1 删除 utils.py −1 修改 main.py size 2048→3072 未变 readme.md

可复用检查清单

检查项通过条件
快照键为相对路径换机器/换根目录后仍可对比
JSON 排序输出sort_keys=True,同状态两次生成字节一致
mtime 精度快速修改能被检出,否则改用 st_mtime_ns 或哈希
目录不参与修改modified 列表只含 type=file 的条目
三类结果可解释added/removed/modified 与手动操作一一对应