前言
大家好,我是 倔强青铜三 。欢迎关注我,微信公众号:倔强青铜三。欢迎点赞、收藏、关注,一键三连!
欢迎来到 苦练Python第58天!
今天我们要入门学习的是filecmp
模块。
它能帮你 一键对比文件、目录差异 ,是版本管理、增量同步、测试回滚的 瑞士军刀。
学完它,你将彻底摆脱 md5sum
、diff
、rsync -n
等黑魔法,用纯 Python 优雅地解决"谁动了我的代码"这一灵魂拷问。
🎯 今日收获预览
- 文件级对比:
cmp()
的 快、准、狠 - 目录级对比:
cmpfiles()
的 批量筛查 - 递归对比神器:
dircmp
类 八大数据属性 - 缓存机制与 性能陷阱
- 实战案例:增量部署校验 、单元测试断言 、爬虫断点续传
🧊 热身:为什么不用手撸?
先来个灵魂三问:
- 你要不要考虑 文件权限?
- 你要不要考虑 符号链接?
- 你要不要考虑 大文件内存爆炸?
filecmp 全帮你 封装好了 ,还自带 缓存加速 。
一句话:不要重复造轮子,除非你想加班。
🗡️ 第一式:单文件对决 ------ filecmp.cmp()
✅ 最简用法
python
import filecmp
filecmp.cmp('a.txt', 'b.txt') # 默认浅比较
filecmp.cmp('a.txt', 'b.txt', shallow=False) # 强制读内容
🔍 参数拆解
参数 | 说明 | 默认 |
---|---|---|
f1, f2 |
待比较路径 | 必填 |
shallow=True |
只看 os.stat() 三围(大小、mtime、mode) |
省 IO,速度起飞 |
shallow=False |
逐字节比对 | 慢但准 |
💡 坑位提醒
- mtime 精度 在 FAT32 只有 2 秒,NTFS 可到 100 ns。
- 如果文件在 1 秒内被反复修改,
shallow=True
会误判。 - 解决:
filecmp.clear_cache()
清缓存,再比一次。
🧰 第二式:批量文件 PK ------ filecmp.cmpfiles()
🎯 场景
你有两个目录 prod/
和 backup/
,想找出 共同文件 里哪些 被篡改。
✅ 代码
python
import filecmp
match, mismatch, errors = filecmp.cmpfiles(
'prod', 'backup',
common=['config.json', 'main.py', 'logo.png']
)
print('✅ 一致:', match)
print('❌ 不同:', mismatch)
print('⚠️ 出错:', errors)
📊 返回值
- match:内容完全一致
- mismatch:内容不同
- errors:文件不存在或无权限
🧬 第三式:目录递归 ------ dircmp
类
🏗️ 创建实例
python
from filecmp import dircmp
dc = dircmp('dir1', 'dir2', ignore=['.git', '__pycache__'])
🧩 八大核心属性
属性 | 含义 | 示例值 |
---|---|---|
left |
左目录路径 | 'dir1' |
right |
右目录路径 | 'dir2' |
left_list |
左目录过滤后列表 | ['a.py', 'b'] |
right_list |
右目录过滤后列表 | ['a.py', 'c'] |
common |
共同存在 | ['a.py'] |
left_only |
仅左 | ['b'] |
right_only |
仅右 | ['c'] |
common_dirs |
共同子目录 | ['sub'] |
common_files |
共同文件 | ['a.py'] |
common_funny |
同名但类型不同 | ['link'] |
same_files |
内容相同 | ['a.py'] |
diff_files |
内容不同 | ['config.ini'] |
funny_files |
无法比较 | ['secret.bin'] |
subdirs |
子目录的 dircmp 实例字典 |
{'sub': <dircmp ...>} |
🖨️ 打印报告
python
dc.report() # 当前层
dc.report_partial_closure() # 向下再一层
dc.report_full_closure() # 递归到底
🧪 实战:递归打印所有差异文件
python
from filecmp import dircmp
def deep_diff(dcmp):
for name in dcmp.diff_files:
print(f"🔥 不同: {dcmp.left}/{name} <-> {dcmp.right}/{name}")
for sub in dcmp.subdirs.values():
deep_diff(sub)
deep_diff(dircmp('v1.0', 'v1.1'))
🧠 缓存机制:速度与准度的博弈
cmp()
与dircmp
默认 缓存 比较结果。- 键 =
(文件路径, os.stat()[:3])
。 - 如果 mtime 精度低 或 快速修改 ,用
filecmp.clear_cache()
刷新。
🎯 实战 1:增量部署校验
需求:上线前,确认 dist/
与线上 /var/www/
只有预期差异。
python
import filecmp, sys
dc = filecmp.dircmp('dist', '/var/www')
if dc.diff_files or dc.left_only or dc.right_only:
dc.report_full_closure()
sys.exit(1)
print('✅ 部署包与线上一致,放心上线!')
🎯 实战 2:单元测试断言
需求:测试生成的报表 report.xlsx
是否与黄金文件一致。
python
import filecmp, unittest
class TestReport(unittest.TestCase):
def test_same(self):
self.assertTrue(
filecmp.cmp('report.xlsx', 'golden/report.xlsx', shallow=False)
)
🎯 实战 3:爬虫断点续传
需求:抓取图片前,先跳过已存在的文件。
python
import os, filecmp, requests
def download(url, path):
if os.path.exists(path):
resp = requests.get(url, stream=True)
with open('tmp', 'wb') as f:
for chunk in resp.iter_content(1024):
f.write(chunk)
if filecmp.cmp('tmp', path, shallow=False):
print('👌 已存在且一致,跳过')
os.remove('tmp')
return
os.replace('tmp', path)
else:
...
🧭 常见坑位汇总
场景 | 症状 | 解决 |
---|---|---|
快速修改文件 | 明明改了却报相同 | clear_cache() |
大文件比较 | 内存飙到 4G | 用外部 hashlib 或分块 |
软链接 | 被当成普通文件 | 手动 os.path.islink() |
Windows 换行 | CRLF vs LF 误判 | 统一 git config core.autocrlf |
🧩 类比时间:filecmp 和女朋友
- cmp() = 快速翻聊天记录(shallow) vs 逐字读长文(deep)。
- cmpfiles() = 闺蜜团帮你 批量查岗。
- dircmp = 把双方手机 全盘扫描,连隐藏文件夹都不放过。
🧪 今日小结
filecmp.cmp()
:单文件,shallow=True 先快后准。filecmp.cmpfiles()
:批量文件,三列表秒出结果。dircmp
:递归目录,八大属性 + 三大报告。- 缓存 = 双刃剑,记得清。
- 实战 = 部署 + 测试 + 爬虫,三板斧走遍天下。
最后感谢阅读!欢迎关注我,微信公众号:
倔强青铜三
。欢迎 点赞、收藏、关注,一键三连!!!