本文目录导读:

Python 实现完整文件快照
#!/usr/bin/env python3
# file_snapshot.py - 文件快照工具
import os
import hashlib
import json
import time
import argparse
from datetime import datetime
from pathlib import Path
class FileSnapshot:
def __init__(self, base_path, exclude_patterns=None):
self.base_path = Path(base_path)
self.exclude_patterns = exclude_patterns or ['.git', 'node_modules', '__pycache__', '.DS_Store']
self.snapshot_data = {}
def compute_hash(self, file_path, block_size=65536):
"""计算文件哈希值"""
sha256 = hashlib.sha256()
try:
with open(file_path, 'rb') as f:
while chunk := f.read(block_size):
sha256.update(chunk)
return sha256.hexdigest()
except (IOError, PermissionError) as e:
return f"ERROR: {str(e)}"
def get_file_info(self, file_path):
"""获取文件详细信息"""
stat = file_path.stat()
return {
'path': str(file_path.relative_to(self.base_path)),
'size': stat.st_size,
'mtime': stat.st_mtime,
'hash': self.compute_hash(file_path),
'permissions': oct(stat.st_mode & 0o777)
}
def create_snapshot(self):
"""创建文件快照"""
for root, dirs, files in os.walk(self.base_path):
# 排除特定目录
dirs[:] = [d for d in dirs if d not in self.exclude_patterns]
root_path = Path(root)
for file in files:
file_path = root_path / file
if file not in self.exclude_patterns:
try:
file_info = self.get_file_info(file_path)
self.snapshot_data[file_info['path']] = file_info
except Exception as e:
print(f"Error processing {file_path}: {e}")
return {
'name': 'file_snapshot',
'created_at': datetime.now().isoformat(),
'base_path': str(self.base_path),
'file_count': len(self.snapshot_data),
'files': self.snapshot_data
}
def save_snapshot(self, output_file):
"""保存快照到文件"""
snapshot = self.create_snapshot()
with open(output_file, 'w', encoding='utf-8') as f:
json.dump(snapshot, f, indent=2, ensure_ascii=False)
print(f"Snapshot saved to {output_file}")
return snapshot
def compare_snapshots(self, old_snapshot_file, new_snapshot_file=None):
"""比较两个快照"""
with open(old_snapshot_file, 'r', encoding='utf-8') as f:
old_snapshot = json.load(f)
if new_snapshot_file:
with open(new_snapshot_file, 'r', encoding='utf-8') as f:
new_snapshot = json.load(f)
else:
new_snapshot = self.create_snapshot()
changes = {
'added': [],
'modified': [],
'removed': []
}
old_files = old_snapshot['files']
new_files = new_snapshot['files']
# 检查新增和修改的文件
for file_path, file_info in new_files.items():
if file_path not in old_files:
changes['added'].append(file_path)
elif file_info['hash'] != old_files[file_path]['hash']:
changes['modified'].append({
'file': file_path,
'old_size': old_files[file_path]['size'],
'new_size': file_info['size'],
'old_mtime': old_files[file_path]['mtime'],
'new_mtime': file_info['mtime']
})
# 检查删除的文件
for file_path in old_files:
if file_path not in new_files:
changes['removed'].append(file_path)
return changes
def restore_from_snapshot(self, snapshot_file, target_dir):
"""从快照恢复到目标目录"""
with open(snapshot_file, 'r', encoding='utf-8') as f:
snapshot = json.load(f)
target_path = Path(target_dir)
target_path.mkdir(parents=True, exist_ok=True)
for file_path, file_info in snapshot['files'].items():
destino = target_path / file_path
source = self.base_path / file_path
if source.exists():
destino.parent.mkdir(parents=True, exist_ok=True)
import shutil
shutil.copy2(source, destino)
print(f"Restored: {file_path}")
# 命令行接口
def main():
parser = argparse.ArgumentParser(description='文件快照工具')
parser.add_argument('action', choices=['create', 'compare', 'restore', 'monitor'],
help='操作类型')
parser.add_argument('--path', required=True, help='要快照的目录路径')
parser.add_argument('--output', help='快照文件路径')
parser.add_argument('--old-snapshot', help='旧快照文件(用于比较)')
parser.add_argument('--target', help='恢复目标目录')
args = parser.parse_args()
snapshotter = FileSnapshot(args.path)
if args.action == 'create':
output = args.output or f'snapshot_{datetime.now().strftime("%Y%m%d_%H%M%S")}.json'
snapshotter.save_snapshot(output)
elif args.action == 'compare':
if not args.old_snapshot:
print("需要指定 --old-snapshot 参数")
return
changes = snapshotter.compare_snapshots(args.old_snapshot)
print(f"新增文件: {len(changes['added'])}")
print(f"修改文件: {len(changes['modified'])}")
print(f"删除文件: {len(changes['removed'])}")
elif args.action == 'restore':
if not args.old_snapshot or not args.target:
print("需要指定 --old-snapshot 和 --target 参数")
return
snapshotter.restore_from_snapshot(args.old_snapshot, args.target)
elif args.action == 'monitor':
# 监控模式
import time
print(f"监控 {args.path} ... (Ctrl+C 停止)")
snap1 = snapshotter.create_snapshot()
try:
while True:
time.sleep(5)
snap2 = snapshotter.create_snapshot()
if snap1['files'] != snap2['files']:
print(f"[{datetime.now().strftime('%H:%M:%S')}] 文件发生变化")
snap1 = snap2
except KeyboardInterrupt:
print("\n监控停止")
if __name__ == '__main__':
main()
Bash Shell 脚本版本(简单快速)
#!/bin/bash
# file_snapshot.sh - 简单文件快照
# 配置文件
SNAPSHOT_DIR="./snapshots"
LOG_FILE="./snapshot.log"
# 初始化
mkdir -p "$SNAPSHOT_DIR"
timestamp=$(date +"%Y%m%d_%H%M%S")
snapshot_file="$SNAPSHOT_DIR/snapshot_$timestamp.txt"
# 生成 MD5 校验清单
echo "生成文件快照: $snapshot_file"
echo "[$timestamp] 开始生成快照" >> "$LOG_FILE"
# 遍历文件并计算哈希
find . -type f ! -path "*/node_modules/*" ! -path "*/.git/*" | while read -r file; do
md5=$(md5sum "$file" | cut -d' ' -f1)
size=$(stat -f%z "$file" 2>/dev/null || stat -c%s "$file")
echo "$md5|$size|$file" >> "$snapshot_file"
done
echo "快照完成"
echo "[$timestamp] 快照完成: $snapshot_file" >> "$LOG_FILE"
# 比较函数
compare_snapshots() {
old_snapshot=$1
new_snapshot=$2
if [ ! -f "$old_snapshot" ] || [ ! -f "$new_snapshot" ]; then
echo "错误:快照文件不存在"
exit 1
fi
echo "新增文件:"
comm -13 <(cut -d'|' -f3 "$old_snapshot" | sort) <(cut -d'|' -f3 "$new_snapshot" | sort)
echo "删除文件:"
comm -23 <(cut -d'|' -f3 "$old_snapshot" | sort) <(cut -d'|' -f3 "$new_snapshot" | sort)
echo "修改文件:"
# 类似文件但MD5不同
grep -f <(cut -d'|' -f3 "$old_snapshot") "$new_snapshot" | sort > /tmp/new_sorted.txt
grep -f <(cut -d'|' -f3 "$new_snapshot") "$old_snapshot" | sort > /tmp/old_sorted.txt
diff /tmp/old_sorted.txt /tmp/new_sorted.txt | grep "^[<>]" | grep -v "^\*\*\*"
}
# 主菜单
case "$1" in
create)
;;
compare)
if [ $# -eq 3 ]; then
compare_snapshots "$2" "$3"
else
echo "用法: $0 compare <旧快照> <新快照>"
fi
;;
*)
echo "用法: $0 {create|compare <old> <new>}"
;;
esac
PowerShell 脚本(Windows)
# file_snapshot.ps1 - Windows 文件快照
param(
[string]$Path = ".",
[string]$Action = "create",
[string]$OutputFile = "",
[string]$ComparisonFile = ""
)
class FileSnapshot {
[string]$Path
[string]$Timestamp
[int]$FileCount = 0
[hashtable]$Files = @{}
FileSnapshot([string]$path) {
$this.Path = $path
$this.Timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
}
[void]Create() {
Get-ChildItem $this.Path -Recurse -File -Exclude *.dll,*.exe | ForEach-Object {
try {
$hash = Get-FileHash $_.FullName -Algorithm MD5
$relativePath = $_.FullName.Replace((Resolve-Path $this.Path).Path + "\", "")
$this.Files[$relativePath] = @{
Hash = $hash.Hash
Size = $_.Length
Modified = $_.LastWriteTime.Ticks
FullPath = $_.FullName
}
$this.FileCount++
} catch {}
}
}
[string]ToJson() {
$this | ConvertTo-Json -Depth 3
}
[hashtable]Compare([FileSnapshot]$other) {
$result = @{
Added = @()
Modified = @()
Removed = @()
}
# 检查新增和修改
foreach ($file in $other.Files.Keys) {
if (-not $this.Files.ContainsKey($file)) {
$result.Added += $file
} elseif ($this.Files[$file].Hash -ne $other.Files[$file].Hash) {
$result.Modified += $file
}
}
# 检查删除
foreach ($file in $this.Files.Keys) {
if (-not $other.Files.ContainsKey($file)) {
$result.Removed += $file
}
}
return $result
}
[void]Save([string]$filename) {
$json = $this.ToJson()
$filename = $filename -replace '[^a-zA-Z0-9\-_\.]', '_'
$filename = "snapshot_$(Get-Date -Format 'yyyyMMdd_HHmmss').json"
$json | Out-File $filename -Encoding utf8
Write-Host "快照已保存: $filename"
}
static [FileSnapshot]Load([string]$filename) {
$json = Get-Content $filename -Raw
return $json | ConvertFrom-Json
}
}
# 主程序
switch ($Action) {
"create" {
$snapshot = [FileSnapshot]::new((Resolve-Path $Path).Path)
$snapshot.Create()
$snapshot.Save($OutputFile)
Write-Host "创建快照完成: $((Resolve-Path $Path).Path) - $($snapshot.FileCount) 个文件"
}
"compare" {
if ($ComparisonFile) {
$oldSnapshot = [FileSnapshot]::Load($ComparisonFile)
$newSnapshot = [FileSnapshot]::new((Resolve-Path $Path).Path)
$newSnapshot.Create()
$changes = $oldSnapshot.Compare($newSnapshot)
Write-Host "=== 文件变化分析 ==="
Write-Host "新增文件: $($changes.Added.Count)"
$changes.Added | ForEach-Object { Write-Host " + $_" }
Write-Host "修改文件: $($changes.Modified.Count)"
$changes.Modified | ForEach-Object { Write-Host " ~ $_" }
Write-Host "删除文件: $($changes.Removed.Count)"
$changes.Removed | ForEach-Object { Write-Host " - $_" }
} else {
Write-Error "比较模式需要指定 ComparisonFile 参数"
}
}
"monitor" {
Write-Host "开始监控 $Path ... (Ctrl+C 停止)"
$firstRun = $true
$oldSnapshot = $null
while ($true) {
$newSnapshot = [FileSnapshot]::new((Resolve-Path $Path).Path)
$newSnapshot.Create()
if ($firstRun) {
$oldSnapshot = $newSnapshot
$firstRun = $false
} else {
$changes = $oldSnapshot.Compare($newSnapshot)
if (($changes.Added.Count + $changes.Modified.Count + $changes.Removed.Count) -gt 0) {
Write-Host "[$(Get-Date -Format 'HH:mm:ss')] 检测到文件变化:"
$changes.Added | ForEach-Object { Write-Host " + 新增: $_" }
$changes.Modified | ForEach-Object { Write-Host " ~ 修改: $_" }
$changes.Removed | ForEach-Object { Write-Host " - 删除: $_" }
}
$oldSnapshot = $newSnapshot
}
Start-Sleep -Seconds 5
}
}
}
使用说明
Python 版本(推荐)
# 创建快照 python file_snapshot.py create --path /your/directory --output snapshot.json # 比较快照 python file_snapshot.py compare --path /your/directory --old-snapshot old.json # 恢复快照 python file_snapshot.py restore --path /source/directory --old-snapshot snapshot.json --target /restore/directory # 实时监控 python file_snapshot.py monitor --path /your/directory
Bash 版本
# 创建快照 ./file_snapshot.sh create # 比较两个快照 ./file_snapshot.sh compare old_snapshot.txt new_snapshot.txt
PowerShell 版本
# 创建快照 .\file_snapshot.ps1 -Path "C:\your\directory" -Action create # 比较快照 .\file_snapshot.ps1 -Path "C:\your\directory" -Action compare -ComparisonFile "snapshot_20240101_120000.json" # 实时监控 .\file_snapshot.ps1 -Path "C:\your\directory" -Action monitor
这些脚本都能实现基本的文件快照功能,Python版本功能最完整,支持安全、修改、恢复等功能;Bash版本适合Linux/Mac系统快速使用;PowerShell适合Windows环境,选择哪个取决于你的具体需求和使用环境。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播