Модуль Python zipfile ошибочно считает, что у меня есть zipfile, который охватывает несколько дисков, выдает ошибку BadZipfile
У меня есть zip-файл объемом 1,4 ГБ, и я пытаюсь выдать каждого члена подряд. Модуль zipfile продолжает выдавать исключение BadZipfile, заявляя, что
msgstr "zipfile.BadZipfile: zipfiles, охватывающие несколько дисков, не поддерживаются".
Вот мой код:
import zipfile
def iterate_members(zip_file_like_object):
zflo = zip_file_like_object
assert zipfile.is_zipfile(zflo) # Here is where the error happens.
# If I comment out the assert, the same error gets thrown on this next line:
with zipfile.ZipFile(zflo) as zip:
members = zip.namelist()
for member in members:
yield member
fn = "filename.zip"
iterate_members(open(fn, 'rb'))
Я использую Python 2.7.3. Я пробовал на Windows 8 и Ubuntu с тем же результатом. Любая помощь очень ценится.
4 ответа
Я получаю ту же ошибку в похожем файле, хотя я использую Python 3.4
Смог исправить это, отредактировав строку 205 в исходном коде zipfile.py:
if diskno != 0 or disks != 1:
raise BadZipFile("zipfiles that span multiple disks are not supported")
чтобы:
if diskno != 0 or disks > 1:
Надеюсь это поможет
Быстрое исправление, установите zipfile38, используя:
pip install zipfile38
И используйте его в коде так же, как и раньше.
import zipfile38 as zipfile
#your code goes here
Возможно, стоит проверить, используете ли вы шифрование deflate64, и если да, то вы можете
pip install zipfile-deflate64
и
import zipfile_deflate64 as zipfile
Затем попробуйте запустить и посмотрите, исправит ли это ситуацию. Возможно, нет, но было бы быстро проверить.
Это исправлено в более новых версиях Python, в которых применяется исправление, предложенное @josselin. Для более старых версий Python вы можете избежать установки стороннего пакета или изменения исходного кода с помощью обезьяньего исправления. Это некрасиво, но свою работу выполнит:
import zipfile
import struct
# Monkey-patch zipfile._EndRecData64
def _EndRecData64(fpin, offset, endrec):
"""
Read the ZIP64 end-of-archive records and use that to update endrec
"""
try:
fpin.seek(offset - zipfile.sizeEndCentDir64Locator, 2)
except OSError:
# If the seek fails, the file is not large enough to contain a ZIP64
# end-of-archive record, so just return the end record we were given.
return endrec
data = fpin.read(zipfile.sizeEndCentDir64Locator)
if len(data) != zipfile.sizeEndCentDir64Locator:
return endrec
sig, diskno, reloff, disks = struct.unpack(
zipfile.structEndArchive64Locator, data)
if sig != zipfile.stringEndArchive64Locator:
return endrec
if diskno != 0 or disks > 1:
raise zipfile.BadZipFile(
"zipfiles that span multiple disks are not supported")
# Assume no 'zip64 extensible data'
fpin.seek(
offset - zipfile.sizeEndCentDir64Locator - zipfile.sizeEndCentDir64, 2)
data = fpin.read(zipfile.sizeEndCentDir64)
if len(data) != zipfile.sizeEndCentDir64:
return endrec
sig, sz, create_version, read_version, disk_num, disk_dir, \
dircount, dircount2, dirsize, diroffset = \
struct.unpack(zipfile.structEndArchive64, data)
if sig != zipfile.stringEndArchive64:
return endrec
# Update the original endrec using data from the ZIP64 record
endrec[zipfile._ECD_SIGNATURE] = sig
endrec[zipfile._ECD_DISK_NUMBER] = disk_num
endrec[zipfile._ECD_DISK_START] = disk_dir
endrec[zipfile._ECD_ENTRIES_THIS_DISK] = dircount
endrec[zipfile._ECD_ENTRIES_TOTAL] = dircount2
endrec[zipfile._ECD_SIZE] = dirsize
endrec[zipfile._ECD_OFFSET] = diroffset
return endrec
# Overwrite _EndRecData64 with the fixed version
zipfile._EndRecData64 = _EndRecData64