Удалить файл из zipfile с помощью модуля ZipFile - программирование
Подтвердить что ты не робот

Удалить файл из zipfile с помощью модуля ZipFile

Единственный способ, которым я приступил к удалению файла из zip файла, - создать временный zip файл без файла, который нужно удалить, а затем переименуйте его в исходное имя файла.

В python 2.4 класс ZipInfo имел атрибут file_offset, поэтому было возможно создать второй zip файл и скопировать данные в другой файл без распаковки/повторного сжатия.

Этот file_offset отсутствует в python 2.6, так есть ли другой вариант, чем создание другого zip файла, распаковывая каждый файл, а затем повторно сбрасывая его?

Возможно, существует прямой способ удаления файла в zip файле, я искал и ничего не нашел.

4b9b3361

Ответ 1

Следующий фрагмент работал у меня (удаляет все *.exe файлы из архива Zip):

zin = zipfile.ZipFile ('archive.zip', 'r')
zout = zipfile.ZipFile ('archve_new.zip', 'w')
for item in zin.infolist():
    buffer = zin.read(item.filename)
    if (item.filename[-4:] != '.exe'):
        zout.writestr(item, buffer)
zout.close()
zin.close()

Если вы все прочитаете в памяти, вы можете устранить необходимость в втором файле. Тем не менее, этот сниппс все-таки пересчитывает все.

После более тщательного осмотра ZipInfo.header_offset является смещением от начала файла. Имя вводит в заблуждение, но основной заголовок Zip фактически хранится в конце файла. Мой hex-редактор подтверждает это.

Таким образом, проблема, с которой вы столкнетесь, заключается в следующем: вам нужно также удалить запись в главном заголовке или указать на файл, который больше не существует. Если оставить основной заголовок неповрежденным, может работать, если вы также сохраните локальный заголовок файла, который вы удаляете, но я не уверен в этом. Как вы это сделали со старым модулем?

Без изменения основного заголовка я получаю сообщение об ошибке "Отсутствие X байтов в zip файле", когда я его открываю. Это может помочь вам узнать, как изменить основной заголовок.

Ответ 2

Не очень элегантный, но вот как я это сделал:

import subprocess
import zipfile

z = zipfile.ZipFile(zip_filename)

files_to_del = filter( lambda f: f.endswith('exe'), z.namelist()]

cmd=['zip', '-d', zip_filename] + files_to_del
subprocess.check_call(cmd)

# reload the modified archive
z = zipfile.ZipFile(zip_filename)

Ответ 3

Подпрограмма delete_from_zip_file от ruamel.std.zipfile ¹ позволяет вам удалять файл по его полному пути в ZIP-архиве или на основе (re). Например. вы можете удалить все .exe файлы из test.zip с помощью

from ruamel.std.zipfile import delete_from_zip_file

delete_from_zip_file('test.zip', pattern='.*.exe')  

(обратите внимание на точку перед *).

Это работает аналогично решению mdm (включая необходимость рекомпрессии), но воссоздает ZIP файл в памяти (используя класс InMemZipFile()), перезаписывая старый файл после его полного чтения.


¹ Отказ от ответственности: я являюсь автором этого пакета.