Python – извлечение файлов из большого (6GB +) zip-файла

У меня есть сценарий Python где мне нужно извлечь содержимое ZIP-файла. Однако zip-файл имеет размер более 6 ГБ.

Существует много информации о zlib и zipfile модулях, однако я не могу найти ни одного подхода, который работает в моем случае. У меня есть код:

 with zipfile.ZipFile(fname, "r") as z: try: log.info("Extracting %s " %fname) head, tail = os.path.split(fname) z.extractall(folder + "/" + tail) except zipfile.BadZipfile: log.error("Bad Zip file") except zipfile.LargeZipFile: log.error("Zip file requires ZIP64 functionality but that has not been enabled (ie, too large)") except zipfile.error: log.error("Error decompressing ZIP file") 

Я знаю, что мне нужно установить allowZip64 в true но я не уверен, как это сделать. Тем не менее, даже LargeZipFile исключение LargeZipFile не выбрасывается, но вместо этого BadZipFile исключение BadZipFile . Понятия не имею почему.

Кроме того, это лучший подход для обработки извлечения архива ZIP на 6 ГБ ???

Обновление: изменение исключения BadZipfile :

 except zipfile.BadZipfile as inst: log.error("Bad Zip file") print type(inst) # the exception instance print inst.args # arguments stored in .args print inst 

показывает:

 <class 'zipfile.BadZipfile'> ('Bad magic number for file header',) 

Обновление № 2:

Полная трассировка показывает

 BadZipfile Traceback (most recent call last) <ipython-input-1-8d34a9f58f6a> in <module>() 6 for member in z.infolist(): 7 print member.filename[-70:], ----> 8 f = z.open(member, 'r') 9 size = 0 10 while True: /Users/brspurri/anaconda/python.app/Contents/lib/python2.7/zipfile.pyc in open(self, name, mode, pwd) 965 fheader = struct.unpack(structFileHeader, fheader) 966 if fheader[_FH_SIGNATURE] != stringFileHeader: --> 967 raise BadZipfile("Bad magic number for file header") 968 969 fname = zef_file.read(fheader[_FH_FILENAME_LENGTH]) BadZipfile: Bad magic number for file header 

Запуск кода:

 import sys import zipfile with open(zip_filename, 'rb') as zf: z = zipfile.ZipFile(zf, allowZip64=True) z.testzip() doesn't output anything. 

Проблема в том, что у вас поврежденный zip-файл. Я могу добавить более подробную информацию о коррупции ниже, но сначала практические вещи:

Вы можете использовать этот фрагмент кода, чтобы сообщить, какой член в архиве поврежден. Однако print z.testzip() уже скажет вам то же самое. И zip -T или unzip в командной строке также должны предоставить вам эту информацию с соответствующей многословием.


Итак, что вы с этим поделаете?

Ну, очевидно, если вы можете получить неповрежденную копию файла, сделайте это.

Если нет, если вы хотите просто пропустить плохой файл и извлечь все остальное, это довольно просто – в основном тот же код, что и фрагмент, связанный выше:

 with open(sys.argv[1], 'rb') as zf: z = zipfile.ZipFile(zf, allowZip64=True) for member in z.infolist(): try: z.extract(member) except zipfile.error as e: # log the error, the member.filename, whatever 

Номер Bad magic number for file header сообщения об исключении Bad magic number for file header означает, что zipfile смог успешно открыть zip-файл, проанализировать его каталог, найти информацию для члена, найти этого члена в архиве и прочитать заголовок этого элемента – все это означает, что у вас, вероятно, нет проблем с zip64. Однако, когда он читал этот заголовок, у него не было ожидаемой «волшебной» подписи PK\003\004 . Это значит, что архив поврежден.

Тот факт, что коррупция происходит точно в 4294967296, очень сильно указывает на то, что у вас была 64-битная проблема где-то вдоль цепочки, потому что это точно 2 ** 32.


Средство zip / unzip командной строки имеет некоторые обходные пути для решения общих причин коррупции, которые приводят к таким проблемам. похоже, что эти обходные пути могут работать для этого архива, учитывая, что вы получаете предупреждение, но все файлы, по-видимому, восстанавливаются. В библиотеке zipfile Python нет этих обходных решений, и я сомневаюсь, что вы сами сами хотите написать свой собственный zip код.

Однако это открывает двери для еще двух возможностей:

Во-первых, zip может восстановить zip-файл для вас, используя флаг -F из -FF . (Прочтите man-страницу или zip -h или спросите на сайте, таком как SuperUser, если вам нужна помощь.)

И если все остальное не удается, вы можете запустить инструмент unzip из Python вместо использования zipfile , например:

 subprocess.check_output(['unzip', fname]) 

zipfile , это дает вам гораздо меньше гибкости и мощности, чем модуль zipfile , но вы все равно не используете какую-либо гибкость; вы просто вызываете extractall .