【问题标题】:Verify zip files in python在 python 中验证 zip 文件
【发布时间】:2017-02-21 16:22:42
【问题描述】:

我需要验证 python 应用程序生成的 zip 文件的内容。我希望每次我们运行该应用程序时,它都会生成具有相同内容的完全相同的 zip 文件(当提供相同的输入时)。这里所说的内容,是指被压缩的文件的内容,而不是这些文件或 zip 文件的元信息。

问题是 zip 文件保留了一些元信息,例如每个文件的创建时间,每次运行应用程序时这些信息都不同。不幸的是,这些 zip 文件可能包含数百万个小文件,这使得提取和计算每个小文件的哈希值非常不愉快。

进行此类测试的好方法是什么?我一直在尝试 hashlib 中的“md5”方法,即将 zip 文件的 md5 值与之前计算的值进行比较。但是,每次运行应用程序时 md5 值都不同,因为元信息不同。知道我该怎么做这个测试吗?如果可能的话,我不介意使用相同的元信息提取和重新压缩它。请注意,zip 文件包含多层目录。

【问题讨论】:

  • 您要使用 md5 或内容验证一个 zip 文件与其他 zip 文件吗?
  • @v.coder 我正在为应用程序编写一个测试模块,期望应用程序每次生成一个具有相同内容的 zip 文件。
  • 所以您正在验证 zip 文件的内容?
  • @v.coder。是的,这里只有内容重要。

标签: python zip md5 shutil


【解决方案1】:

我喜欢 Laurent S 的基本理念,即确保您在运行测试时拥有完全相同的条件。只要您不考虑安全问题,我就同意使用 md5。

由于您对每次运行都不同的元数据非常不明确,所以我很好奇并做了一个简短的测试。

zip t1 t00*png 
zip t2 t00*png

现在进行一些元更改:

touch t00*.png
zip t3 t00*png

结果:

md5sum *.zip
760a4a1c52f3bc6cdd29c1fff7b94c1f  t1.zip
760a4a1c52f3bc6cdd29c1fff7b94c1f  t2.zip
83a8dcb9fe0d50e7b2b8012c8842005e  t3.zip

这意味着 - 最后我的 zip [1] 版本确实会产生可重复的内容,只要不更改元数据。

您的更改 - 根据定义 - 不是文件内容的一部分(例如,JPEG 的 EXIF 数据 也是元数据,但是文件的一部分 - 而文件访问日期 不是)。否则你根本没有机会使用任何散列函数。

因此,如果您想要在文件内容相同但元数据(文件系统的元数据)不同的情况下获得可比较的结果,您只需调整元数据即可节省大量工作。

当您在这里进行某种单元测试时,您甚至可以使用它来验证 md5-sum 是否相同调整元数据和不同没有

概念证明:

touch t00*.png -d '2000-01-01T0:00'
zip t1 t00*png
touch t00*.png -d
zip t2 t00*png
touch t00*.png -d '2000-01-01T0:00'
zip t3 t00*png

结果:

md5sum *.zip
a1e713c1d91a0042b37043c83bb98d1b  t1.zip
3085aa53bee69df4be783636b87ed62c  t2.zip
a1e713c1d91a0042b37043c83bb98d1b  t3.zip

最后但同样重要的是,您可以尝试调整 ZIP 文件中与您的测试无关的区域。由于 ZIP 似乎是一种表现良好的容器格式,我的更改的元数据以整齐的距离显示 - 强化了我的假设,即它们是每个文件的页眉/页脚:

cat t1.zip| xxd -ps -c 20 > t1.hd
cat t2.zip| xxd -ps -c 20 > t2.hd
diff t1.hd t2.hd
1c1
< 504b03041400000008000000212822aad7cacc0b
---
> 504b0304140000000800c37a574a22aad7cacc0b
3c3
< 09000370356d3870356d3875780b000104e80300
---
> 0900030df0ae580df0ae5875780b000104e80300
3432c3432
< 6082504b030414000000080000002128143698a4
---
> 6082504b0304140000000800c37a574a143698a4
3434c3434
< 555409000370356d3870356d3875780b000104e8
---
> 55540900030df0ae580df0ae5875780b000104e8
19691,19693c19691,19693
...

请注意由元数据更改引起的明显最小的差异。

[1] Linux 4.9.9-1-ARCH #1 SMP PREEMPT Thu Feb 9 19:07:09 CET 2017 x86_64 GNU/Linux, <br>
Zip 3.0 (July 5th 2008), by Info-ZIP, Compiled with gcc 5.3.0 for Unix (Linux ELF) on Jan 12 2016.

【讨论】:

  • 我确认这适用于同一目录下的文件。但是我无法使它适用于具有多级目录的文件。我使用的是命令: find TestDir -exec touch -d '2000-01-01T0:00' {} \;我确信除了“。”之外没有其他隐藏文件。和目录中的“..”。你知道我在这里错过了什么吗?非常感谢。
  • 我可以使用子目录确认一些不稳定性。第一个猜测是添加文件时的随机顺序。你使用通配符压缩吗?您能否尝试“手动”压缩一些文件,这意味着每个文件都作为单独的参数?
【解决方案2】:

据我了解,您正在尝试编写自动化测试来验证 zip 文件的内容是否符合您的预期。

md5 似乎是一个很好的选择。现在,如果您在 zip 文件中有与时间相关的数据,我建议您为此使用 https://github.com/spulec/freezegun。它旨在“暂停”时间,以便所有对datetime 函数(now()today()...)的调用都将返回一个已知值。你可以这样做:

from freezegun import freeze_time

def test_zipping():
    with freeze_time("2012-01-14 12:34:56"):
        zipfile = create_zip_file(data)
        md5 = hashlib.md5()
        with open(zipfile_name) , "rb" ) as f:
            data = f.read(block_size)
            if not data:
                break
            md5.update(data)
        assert md5.digest() == expected_md5_value

这样,您应该能够从测试中消除与时间相关的调用的随机性。

(受Get MD5 hash of big files in Python 启发,因为您的 zip 文件似乎足够大)

【讨论】:

  • 感谢@Laurent S。zip 文件的内容与时间无关,它是在创建 zip 文件时,会在 zip 文件的元信息中写入某种时间戳。但我会试试你的建议,看看它是否也冻结了 zip 模块的时间。
  • 不,它对我不起作用。我提取 zip 文件,然后使用 shutil.make_archive() 压缩它们。 md5 值仍然因运行而异。
  • 您是否检查过 zip 算法实际上保证了给定输入的稳定输出?如果没有,可能是您的测试策略不适应?
  • 此时我无法检查,因为我无法控制它写入文件的元信息。被压缩的文件不会随着压缩和解压而改变,这是有保证的。
  • 我的意思是您应该检查 zip 文件格式文档 (pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT) 以验证您尝试做的事情是否有意义。或者docs.python.org/2/library/zipfile.html#zipfile.ZipFile.testzip 可能是解决问题的好方法?
猜你喜欢
  • 2012-09-15
  • 2018-05-16
  • 1970-01-01
  • 1970-01-01
  • 2012-01-30
  • 1970-01-01
  • 1970-01-01
  • 2020-12-18
  • 2014-11-07
相关资源
最近更新 更多