苦练Python第58天:filecmp模块——文件和目录“找不同”的利器

前言

大家好,我是 倔强青铜三 。欢迎关注我,微信公众号:倔强青铜三。欢迎点赞、收藏、关注,一键三连!

欢迎来到 苦练Python第58天

今天我们要入门学习的是filecmp 模块。

它能帮你 一键对比文件、目录差异 ,是版本管理、增量同步、测试回滚的 瑞士军刀

学完它,你将彻底摆脱 md5sumdiffrsync -n 等黑魔法,用纯 Python 优雅地解决"谁动了我的代码"这一灵魂拷问。


🎯 今日收获预览

  • 文件级对比:cmp()快、准、狠
  • 目录级对比:cmpfiles()批量筛查
  • 递归对比神器:dircmp八大数据属性
  • 缓存机制与 性能陷阱
  • 实战案例:增量部署校验单元测试断言爬虫断点续传

🧊 热身:为什么不用手撸?

先来个灵魂三问:

  1. 你要不要考虑 文件权限
  2. 你要不要考虑 符号链接
  3. 你要不要考虑 大文件内存爆炸

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:递归目录,八大属性 + 三大报告
  • 缓存 = 双刃剑,记得清
  • 实战 = 部署 + 测试 + 爬虫,三板斧走遍天下

最后感谢阅读!欢迎关注我,微信公众号:倔强青铜三

欢迎 点赞、收藏、关注,一键三连!!!

相关推荐
倔强青铜三2 小时前
苦练Python第59天:tempfile模块,临时文件自动删!再也不用手动清理到怀疑人生
人工智能·python·面试
stjiejieto2 小时前
AI 重构实体经济:2025 传统产业的智能转型革命
人工智能·重构
IT教程资源2 小时前
(免费分享)基于python的飞机大战游戏
python·游戏·pygame
镰刀韭菜2 小时前
【AI4S】通过单一基础模型双向生成分子的结构和特性
人工智能·分子生成·ai4s·多模态分子预训练模型·spmm·bpe算法
hello 早上好2 小时前
深入理解 SPI:从定义到 Spring Boot 实践
java·spring boot·python
Q741_1472 小时前
C++ 位运算 高频面试考点 力扣 371. 两整数之和 题解 每日一题
c++·算法·leetcode·面试·位运算
likunyuan08302 小时前
概率统计中的数学语言与术语1
人工智能·机器学习·概率论
qq_314810812 小时前
AI与IT人:协作而非替代
人工智能
骑猪兜风2333 小时前
深度解析 ChatGPT 和 Claude 的记忆机制
人工智能·chatgpt·ai编程