【Python】实现一个文件夹快照与比较工具
1. 工具简介
在日常开发、项目管理或备份场景中,我们经常需要知道某个文件夹中的文件是否发生变化,例如:
- 项目源码是否新增或修改文件?
- 数据集是否被不小心删除或篡改?
- 备份文件夹是否和上次一致?
本教程将教你如何编写一个简单的 Python 命令行工具,只基于文件内容哈希值(SHA256) 来检测变化。
2. 功能设计
该工具支持两个核心命令:
命令 | 作用 |
---|---|
create | 创建当前文件夹的快照,保存为 JSON |
compare | 比较当前文件夹与指定快照文件的差异 |
命令行格式:
python snapshot.py <目录路径> <create|compare> <快照文件.json>
示例:
# 创建快照
python snapshot.py ./project create snapshot.json# 比较快照
python snapshot.py ./project compare snapshot.json
3. 核心实现思路
-
遍历文件夹
- 递归遍历指定文件夹中的所有文件,并计算每个文件的 SHA256 哈希值。
-
快照格式
-
将快照保存为 JSON 文件,文件路径使用 POSIX 风格的
/
分隔符,保证跨平台一致性。 -
快照文件结构示例:
{"main.py": "a3f2f9c91b72e9f8d4f2...","data/input.csv": "e49adf91c7dbe23ff03d..." }
-
-
比较逻辑
- 根据快照与当前文件夹的哈希值,分为三类:
- 新增文件:当前存在但快照中没有的文件
- 删除文件:快照中存在但当前不存在的文件
- 修改文件:快照和当前都存在,但哈希值不同
- 根据快照与当前文件夹的哈希值,分为三类:
4. 完整代码
下面是实现该工具的完整 Python 代码,只有一个文件,简单易用。
#!/usr/bin/env python3
import os
import sys
import json
import hashlib
from pathlib import Pathdef calc_file_hash(file_path, chunk_size=8192):"""计算文件的 SHA256 哈希值"""sha256 = hashlib.sha256()try:with open(file_path, "rb") as f:while chunk := f.read(chunk_size):sha256.update(chunk)except Exception as e:print(f"[ERROR] Cannot read file: {file_path}, {e}", file=sys.stderr)return Nonereturn sha256.hexdigest()def create_snapshot(directory: Path, output_file: Path):"""创建快照文件,路径统一为 POSIX 风格"""directory = directory.resolve()snapshot = {}for root, _, files in os.walk(directory):for filename in files:abs_path = Path(root) / filename# 统一使用 "/" 作为分隔符rel_path = abs_path.relative_to(directory).as_posix()file_hash = calc_file_hash(abs_path)if file_hash:snapshot[rel_path] = file_hashwith open(output_file, "w", encoding="utf-8") as f:json.dump(snapshot, f, indent=2, ensure_ascii=False)print(f"[OK] Snapshot created: {output_file}")def compare_snapshot(directory: Path, snapshot_file: Path):"""比较当前目录与快照的差异"""with open(snapshot_file, "r", encoding="utf-8") as f:old_files = json.load(f)base_dir = directory.resolve()current_files = {}for root, _, files in os.walk(base_dir):for filename in files:abs_path = Path(root) / filenamerel_path = abs_path.relative_to(base_dir).as_posix()file_hash = calc_file_hash(abs_path)if file_hash:current_files[rel_path] = file_hash# 计算差异added = [f for f in current_files if f not in old_files]deleted = [f for f in old_files if f not in current_files]modified = [f for f in current_files if f in old_files and current_files[f] != old_files[f]]# 输出结果print("\nAdded files:")for f in added:print(f" + {f}")print("\nDeleted files:")for f in deleted:print(f" - {f}")print("\nModified files:")for f in modified:print(f" * {f}")def main():# 参数格式:python snapshot.py <directory> <create|compare> <snapshot.json>if len(sys.argv) != 4:print("Usage: python snapshot.py <directory> <create|compare> <snapshot.json>")sys.exit(1)directory = Path(sys.argv[1])command = sys.argv[2].lower()snapshot_file = Path(sys.argv[3])if command == "create":create_snapshot(directory, snapshot_file)elif command == "compare":compare_snapshot(directory, snapshot_file)else:print("Error: command must be 'create' or 'compare'")sys.exit(1)if __name__ == "__main__":main()
5. 使用示例
假设有如下目录结构:
myfolder/
├─ file1.txt
├─ file2.txt
└─ subdir/└─ image.png
创建快照
python snapshot.py ./myfolder create snapshot.json
生成的 snapshot.json
内容示例:
{"file1.txt": "a3f2f9c91b72e9f8d4f2c5d9c0c3b...","file2.txt": "b74b9ff174c5e00e3e8f93b4c9f0a...","subdir/image.png": "e49adf91c7dbe23ff03dbf7839273..."
}
修改文件并比较
例如:
- 修改
file2.txt
- 新增
notes.txt
- 删除
subdir/image.png
执行比较命令:
python snapshot.py ./myfolder compare snapshot.json
输出结果:
Added files:+ notes.txtDeleted files:- subdir/image.pngModified files:* file2.txt
6. 总结
通过本教程,我们实现了一个简洁高效的命令行工具,实现了以下功能:
- 记录文件夹的完整快照(基于文件内容哈希)。
- 快速比较当前文件夹与快照的差异。
- 跨平台兼容,结果统一、可读。
该工具非常适合日常开发和运维场景,帮助你高效地管理和追踪文件变化。