如何避免Zipfile.write因文件修改日期导致压缩包哈希变化?
解决Zipfile压缩相同内容哈希不一致的问题
你猜的没错——文件的修改时间、权限等元数据是导致相同内容的文件压缩后哈希不同的罪魁祸首。zip归档里的每个文件条目都会附带这些元数据,哪怕文件内容完全一样,每次生成zip时这些动态变化的元数据都会让最终的包产生差异。
要实现“仅基于内容生成一致哈希的zip包”,核心思路是手动固定所有可变的元数据,不让这些额外信息影响最终的归档结果。下面是具体的实现方法:
具体步骤
- 创建一个固定的
ZipInfo对象,手动设置所有可能变化的元数据(比如修改时间、权限)为固定值 - 读取文件的原始内容,通过
zf.writestr()方法将内容写入zip,而不是用默认的zf.write()(后者会自动读取文件的元数据)
修改后的测试代码
import os import hashlib import zipfile from io import BytesIO from datetime import datetime FILE_PATH = './' SAMPLE_FILE = "zip_test123.txt" # 创建空文件(保持原有逻辑) new_file = os.path.join(FILE_PATH, SAMPLE_FILE) try: open(new_file, 'x') except FileExistsError: os.remove(new_file) open(new_file, 'x') # 准备zip包 data = BytesIO() with zipfile.ZipFile(data, mode='w') as zf: # 创建ZipInfo对象,指定文件名 zip_info = zipfile.ZipInfo(SAMPLE_FILE) # 设置固定的修改时间(用zip格式支持的最早时间,也可设其他固定时间) zip_info.date_time = datetime(1980, 1, 1, 0, 0, 0).timetuple()[:6] # 设置固定的文件权限(普通文件的644权限) zip_info.external_attr = 0o644 << 16 # 外部属性需左移16位符合zip格式要求 # 读取文件内容并写入zip with open(new_file, 'rb') as f: zf.writestr(zip_info, f.read()) zip_cntn = data.getvalue() data.close() print(zip_cntn) print(hashlib.md5(zip_cntn).hexdigest())
关键细节说明
zip_info.date_time:必须是包含年、月、日、时、分、秒的6元组,这里固定为1980年1月1日(zip格式支持的起始时间),确保每次生成的元数据一致zip_info.external_attr:存储文件权限等属性,0o644 << 16是普通文件的标准权限设置,左移16位是zip格式对属性存储的要求- 选用
writestr()而非write():直接写入文件原始内容,避免自动读取文件的动态元数据
这样修改后,只要文件内容不变,每次生成的zip包哈希值就会完全一致了。
内容的提问来源于stack exchange,提问作者Mahyar
相关产品推荐
相关产品推荐

