You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Python比较多卷7Z归档文件夹,找出超1GB差异内容?

问题:对比多卷7Z归档中的文件/文件夹大小变化

我有两个路径,各自存放着多卷.7Z归档文件:

  • 路径A包含4个文件:example1.7z.001, example1.7z.002, example1.7z.003, example1.7z.004(总大小15GB),解压后得到一个20GB的7z文件,再次解压得到40GB的文件夹,其中TEST1文件夹占5GB。
  • 路径B包含5个文件:example2.7z.001, example2.7z.002, example2.7z.003, example2.7z.004, example2.7z.005(总大小20GB),解压后得到22GB的7z文件,再次解压得到50GB的文件夹,其中TEST1文件夹增至7GB,新增TEST2文件夹占1.2GB。

需求:编写Python脚本,输入这两个路径后,输出大小增量超1GB的现有文件/文件夹,或大小超1GB的新增文件/文件夹(本例应返回TEST1和TEST2)。


初步调研的三种方案

1. 使用magic库

magic库仅能检测文件类型、判断两个7Z文件内容是否完全一致,无法获取归档内部文件/文件夹的大小信息,完全满足不了需求,直接排除。

代码示例:

import magic

def compare_7zip_content(file1, file2):
    with open(file1, 'rb') as f1, open(file2, 'rb') as f2:
        m1 = magic.Magic(mime=True)
        m2 = magic.Magic(mime=True)
        
        file1_content = f1.read()
        file2_content = f2.read()

        file1_type = m1.from_buffer(file1_content)
        file2_type = m2.from_buffer(file2_content)
        
        if file1_type == 'application/x-7z-compressed' and file2_type == 'application/x-7z-compressed':
            if file1_content == file2_content:
                return True
            else:
                return False
        else:
            raise ValueError('One or both of the files are not 7zip format')

2. 使用py7zr库

py7zr是Python原生的7Z处理库,支持读取多卷归档的内容信息,无需完全解压文件,效率较高。但你提供的代码存在几个问题:

  • 仅处理单文件7Z,未考虑.7z.001这类多卷归档的情况
  • 直接按顺序zip两个归档的文件列表,会漏掉新增/删除的文件
  • 只计算单个文件的大小差,未处理文件夹的总大小统计

代码示例:

import py7zr
import os

folder1 = '/path/to/folder1'
folder2 = '/path/to/folder2'

for filename in os.listdir(folder1):
    if filename.endswith('.7z'):
        file1 = os.path.join(folder1, filename)
        file2 = os.path.join(folder2, filename)
        with py7zr.SevenZipFile(file1, mode='r') as archive1, \
             py7zr.SevenZipFile(file2, mode='r') as archive2:
            archive1_files = archive1.getnames()
            archive2_files = archive2.getnames()
            for archive1_file, archive2_file in zip(archive1_files, archive2_files):
                size_diff = abs(archive1.getmember(archive1_file).file_size -
                                archive2.getmember(archive2_file).file_size)
                if size_diff >= 1000000000: # 1 GB in bytes
                    print(f"{filename}: {size_diff / 1000000000} GB")

3. 使用7z CLI工具

通过调用系统的7z命令行工具,执行l(列表)命令获取归档内的文件/文件夹信息,再解析输出结果。优点是兼容性好,支持所有7Z特性;缺点是需要系统提前安装7z工具,且解析命令输出需要处理字符串,稳定性依赖于7z的输出格式。


推荐方案及优化思路

优先选择py7zr库,因为它是Python原生库,不需要依赖外部工具,代码可移植性更强。针对需求,需要对原有代码进行以下优化:

优化点说明

  1. 处理多卷归档:py7zr支持自动识别多卷,只需传入分卷的第一个文件(比如example1.7z.001)即可
  2. 统计文件夹总大小:归档中的文件夹本身无大小,需递归累加其下所有文件的大小总和
  3. 完整对比文件集合:既要对比共有项的大小增量,也要检查新增项的大小是否达标

优化后的示例代码

import py7zr
import os
from collections import defaultdict

GB = 1024 * 1024 * 1024  # 二进制1GB,若需十进制统计可改为10**9

def get_archive_size_map(archive_path):
    """获取归档内所有文件/文件夹的大小映射,文件夹值为下属文件总大小"""
    size_map = defaultdict(int)
    with py7zr.SevenZipFile(archive_path, mode='r') as archive:
        for entry in archive.list():
            if entry.is_dir:
                continue
            # 累加文件本身大小
            size_map[entry.filename] += entry.file_size
            # 递归累加所有上级文件夹的大小
            parts = entry.filename.split('/')
            for i in range(1, len(parts)):
                folder_path = '/'.join(parts[:i])
                size_map[folder_path] += entry.file_size
    return size_map

def compare_archives(path_a, path_b):
    # 获取路径下的多卷7Z主文件(.7z.001)
    def get_main_archive(folder):
        for filename in os.listdir(folder):
            if filename.endswith('.7z.001'):
                return os.path.join(folder, filename)
        raise FileNotFoundError(f"路径{folder}中未找到多卷7Z主文件(.7z.001)")
    
    archive_a = get_main_archive(path_a)
    archive_b = get_main_archive(path_b)
    
    size_map_a = get_archive_size_map(archive_a)
    size_map_b = get_archive_size_map(archive_b)
    
    result = []
    
    # 检查共有项的大小增量
    for name in size_map_a:
        if name in size_map_b:
            diff = size_map_b[name] - size_map_a[name]
            if diff > GB:
                result.append(f"{name}(增量:{diff/GB:.2f} GB)")
    
    # 检查新增项的大小
    for name in size_map_b:
        if name not in size_map_a:
            if size_map_b[name] > GB:
                result.append(f"{name}(新增,大小:{size_map_b[name]/GB:.2f} GB)")
    
    return result

# 示例调用
if __name__ == "__main__":
    path_a = "/path/to/folderA"
    path_b = "/path/to/folderB"
    changes = compare_archives(path_a, path_b)
    print("符合条件的文件/文件夹:")
    for item in changes:
        print(f"- {item}")

备选方案:7z CLI实现

如果py7zr遇到兼容性问题(比如特殊压缩算法),可以使用7z CLI,示例代码如下:

import subprocess
import os
from collections import defaultdict

GB = 1024 * 1024 * 1024

def get_archive_size_map_cli(archive_path):
    size_map = defaultdict(int)
    # 执行7z l命令获取详细文件列表
    result = subprocess.run(
        ["7z", "l", "-slt", archive_path],
        capture_output=True,
        text=True,
        check=True
    )
    # 解析输出内容
    current_file = None
    current_size = 0
    for line in result.stdout.splitlines():
        if line.startswith("Path = "):
            current_file = line.split(" = ")[1]
        elif line.startswith("Size = "):
            current_size = int(line.split(" = ")[1])
            if current_file:
                # 累加文件和上级文件夹大小
                parts = current_file.split('/')
                for i in range(1, len(parts)):
                    folder_path = '/'.join(parts[:i])
                    size_map[folder_path] += current_size
                size_map[current_file] += current_size
                current_file = None
    return size_map

# 对比逻辑复用py7zr版本的compare_archives函数即可

方案选择总结

  • 优先选py7zr:Python原生实现,无需外部依赖,代码可控性强,适合大多数场景
  • 次选7z CLI:兼容性拉满,但需要系统安装7z工具,解析输出易受版本影响
  • 排除magic库:仅能做文件类型校验和内容一致性对比,完全满足不了大小统计需求

内容的提问来源于stack exchange,提问作者arielma

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 21:50:39