ZipFile.testzip()在Python 2和Python 3上返回不同的结果

Eth*_*ite 15 python unzip python-2.x zipfile python-3.x

使用zipfile模块在Python中解压缩大型数据文件在Python 2上正常工作,但在Python 3.6.0上产生以下错误:

BadZipFile: Bad CRC-32 for file 'myfile.csv'

我将此跟踪到错误处理代码检查CRC值.

ZipFile.testzip()在Python 2上使用什么都不返回(所有文件都没问题).在Python 3上运行它会返回'myfile.csv'指示该文件的问题.

在Python 2和Python 3上重现的代码(涉及300 MB下载,抱歉):

import zipfile
import urllib
import sys

url = "https://de.iplantcollaborative.org/anon-files//iplant/home/shared/commons_repo/curated/Vertnet_Amphibia_Sep2016/VertNet_Amphibia_Sept2016.zip"

if sys.version_info >= (3, 0, 0):
    urllib.request.urlretrieve(url, "vertnet_latest_amphibians.zip")
else:
    urllib.urlretrieve(url, "vertnet_latest_amphibians.zip")

archive = zipfile.ZipFile("vertnet_latest_amphibians.zip")
archive.testzip()
Run Code Online (Sandbox Code Playgroud)

有没有人理解为什么存在这种差异,以及是否有办法让Python 3使用以下方法正确提取文件:

archive.extract("vertnet_latest_amphibians.csv")
Run Code Online (Sandbox Code Playgroud)

小智 6

我无法从存档中提取Python 3.调查(在Mac OS X上)的一些结果可能会有所帮助.

检查存档的运行状况

将文件设为只读以防止意外更改:

$ chmod -w vertnet_latest_amphibians.zip 
$ ls -lh vertnet_latest_amphibians.zip 
-r--r--r-- 1 lawh 2045336417 296M Jan  6 10:10 vertnet_latest_amphibians.zip
Run Code Online (Sandbox Code Playgroud)

使用zip和检查存档unzip:

$ zip -T vertnet_latest_amphibians.zip
test of vertnet_latest_amphibians.zip OK

$ unzip -t vertnet_latest_amphibians.zip
Archive:  vertnet_latest_amphibians.zip
    testing: VertNet_Amphibia_eml.xml   OK
    testing: __MACOSX/                OK
    testing: __MACOSX/._VertNet_Amphibia_eml.xml   OK
    testing: vertnet_latest_amphibians.csv   OK
    testing: __MACOSX/._vertnet_latest_amphibians.csv   OK
No errors detected in compressed data of vertnet_latest_amphibians.zip
Run Code Online (Sandbox Code Playgroud)

正如@ sam-mussmann所发现的,7z报告CRC错误:

$ 7z t vertnet_latest_amphibians.zip 

7-Zip [64] 16.02 : Copyright (c) 1999-2016 Igor Pavlov : 2016-05-21
p7zip Version 16.02 (locale=utf8,Utf16=on,HugeFiles=on,64 bits,4 CPUs x64)

Scanning the drive for archives:
1 file, 309726398 bytes (296 MiB)

Testing archive: vertnet_latest_amphibians.zip
--
Path = vertnet_latest_amphibians.zip
Type = zip
Physical Size = 309726398

ERROR: CRC Failed : vertnet_latest_amphibians.csv

Sub items Errors: 1

Archives with Errors: 1

Sub items Errors: 1
Run Code Online (Sandbox Code Playgroud)

zipunzip他们都很老了; 7z很新:

$ zip -v | head -2
Copyright (c) 1990-2008 Info-ZIP - Type 'zip "-L"' for software license.
This is Zip 3.0 (July 5th 2008), by Info-ZIP.

$ unzip -v | head -1
UnZip 6.00 of 20 April 2009, by Debian. Original by Info-ZIP.

$ 7z --help |head -3

7-Zip [64] 16.02 : Copyright (c) 1999-2016 Igor Pavlov : 2016-05-21
p7zip Version 16.02 (locale=utf8,Utf16=on,HugeFiles=on,64 bits,4 CPUs x64)
Run Code Online (Sandbox Code Playgroud)

提取

使用unzip:

$ time unzip vertnet_latest_amphibians.zip vertnet_latest_amphibians.csv
Archive:  vertnet_latest_amphibians.zip
  inflating: vertnet_latest_amphibians.csv  

real    0m17.201s
user    0m14.281s
sys 0m2.460s
Run Code Online (Sandbox Code Playgroud)

使用Python 2.7.13进行提取,使用zipfile的命令行界面简洁:

$ time ~/local/python-2.7.13/bin/python2 -m zipfile -e vertnet_latest_amphibians.zip .

real    0m19.491s
user    0m12.996s
sys 0m5.897s
Run Code Online (Sandbox Code Playgroud)

如您所见,Python 3.6.0(也是3.4.5和3.5.2)报告错误的CRC

假设1:存档包含一个错误的CRC zip,unzip并且Python 2.7.13无法检测到; 7z和Python 3.4-3.6都在做正确的事情.

假设2:档案很好; 7z和Python 3.4-3.6都包含一个bug.

考虑到这些工具的相对年龄,我猜想H1是正确的.

解决方法

如果您不使用Windows并信任存档的内容,则使用常规shell命令可能更为简单.就像是:

wget <the-long-url> -O /tmp/vertnet_latest_amphibians.zip
unzip /tmp/vertnet_latest_amphibians.zip vertnet_latest_amphibians.csv
rm -rf /tmp/vertnet_latest_amphibians.zip
Run Code Online (Sandbox Code Playgroud)

或者您可以unzip在Python中执行:

import os
os.system('unzip vertnet_latest_amphibians.zip vertnet_latest_amphibians.csv')
Run Code Online (Sandbox Code Playgroud)

附带的

捕获ImportError比检查Python解释器的版本更简洁:

try:
    from urllib.request import urlretrieve
except ImportError:
    from urllib import urlretrieve
Run Code Online (Sandbox Code Playgroud)


Nic*_*teo 5

CRC值正常.zip中记录的'vertnet_latest_amphibians.csv'的CRC为0x87203305.提取后,这确实是文件的CRC.

但是,给定的未压缩大小不正确.zip文件记录的压缩大小为309,723,024字节,未压缩大小为292,198,614字节(更小!).实际上,未压缩文件是4,587,165,910字节(4.3 GiB).这大于4位GiB阈值,其中32位计数器中断.

您可以像这样修复它(这至少在Python 3.5.2中有效):

archive = zipfile.ZipFile("vertnet_latest_amphibians.zip")
archive.getinfo("vertnet_latest_amphibians.csv").file_size += 2**32
archive.testzip() # now passes
archive.extract("vertnet_latest_amphibians.csv") # now works
Run Code Online (Sandbox Code Playgroud)