Модуль 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
Другие вопросы по тегам