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. 總結
通過本教程,我們實現了一個簡潔高效的命令行工具,實現了以下功能:
- 記錄文件夾的完整快照(基于文件內容哈希)。
- 快速比較當前文件夾與快照的差異。
- 跨平臺兼容,結果統一、可讀。
該工具非常適合日常開發和運維場景,幫助你高效地管理和追蹤文件變化。