Delete File from Zipfile with the Zipfile Module

How do I delete or replace a file in a zip archive?

From http://docs.python.org/2/library/zipfile

ZipFile.namelist()
Return a list of archive members by name.

So it is trivial to get hold of the members list before appending to the file and performing a check operation against the list of existing members within the archive.

In addition: removing from a ZIP file is not supported. You need to write a new archive
if needed and copy over existing files and omit the file to be removed.

See also

Delete file from zipfile with the ZipFile Module

Python remove entry from zipfile

After some intensive debugging, I'm quite sure something went wrong with moving the remaining chunks. (The ones stored after the removed file) So I went ahead and rewrote this code part, so it copies these files/chunks each at a time. Also I rewrite the file header for each of them (to make sure it is valid) and the central directory at the end of the zipfile.
My remove function now looks like this:

def remove(self, member):
"""Remove a file from the archive. Only works if the ZipFile was opened
with mode 'a'."""

if "a" not in self.mode:
raise RuntimeError('remove() requires mode "a"')
if not self.fp:
raise RuntimeError(
"Attempt to modify ZIP archive that was already closed")
fp = self.fp

# Make sure we have an info object
if isinstance(member, ZipInfo):
# 'member' is already an info object
zinfo = member
else:
# Get info object for member
zinfo = self.getinfo(member)

# start at the pos of the first member (smallest offset)
position = min([info.header_offset for info in self.filelist]) # start at the beginning of first file
for info in self.filelist:
fileheader = info.FileHeader()
# is member after delete one?
if info.header_offset > zinfo.header_offset and info != zinfo:
# rewrite FileHeader and copy compressed data
# Skip the file header:
fp.seek(info.header_offset)
fheader = fp.read(sizeFileHeader)
if fheader[0:4] != stringFileHeader:
raise BadZipFile("Bad magic number for file header")

fheader = struct.unpack(structFileHeader, fheader)
fname = fp.read(fheader[_FH_FILENAME_LENGTH])
if fheader[_FH_EXTRA_FIELD_LENGTH]:
fp.read(fheader[_FH_EXTRA_FIELD_LENGTH])

if zinfo.flag_bits & 0x800:
# UTF-8 filename
fname_str = fname.decode("utf-8")
else:
fname_str = fname.decode("cp437")

if fname_str != info.orig_filename:
if not self._filePassed:
fp.close()
raise BadZipFile(
'File name in directory %r and header %r differ.'
% (zinfo.orig_filename, fname))

# read the actual data
data = fp.read(fheader[_FH_COMPRESSED_SIZE])

# modify info obj
info.header_offset = position
# jump to new position
fp.seek(info.header_offset, 0)
# write fileheader and data
fp.write(fileheader)
fp.write(data)
if zinfo.flag_bits & _FHF_HAS_DATA_DESCRIPTOR:
# Write CRC and file sizes after the file data
fp.write(struct.pack("<LLL", info.CRC, info.compress_size,
info.file_size))
# update position
fp.flush()
position = fp.tell()

elif info != zinfo:
# move to next position
position = position + info.compress_size + len(fileheader) + self._get_data_descriptor_size(info)

# Fix class members with state
self.start_dir = position
self._didModify = True
self.filelist.remove(zinfo)
del self.NameToInfo[zinfo.filename]

# write new central directory (includes truncate)
fp.seek(position, 0)
self._write_central_dir()
fp.seek(self.start_dir, 0) # jump to the beginning of the central directory, so it gets overridden at close()

You can find the complete code in the latest revision of the gist: https://gist.github.com/FreakyBytes/30a6f9866154d82f1c3863f2e4969cc4

or in the repo of the library I'm writing: https://github.com/FreakyBytes/pyCombineArchive

Not able to delete the zip file using os or shutil module

To delete a zip folder via python you need to use os.remove(myzip.zip) because it is treated as a file not a folder so shutil.rmtree() doesnt work.

Source: i learnt this the hard way

Deleting a folder in a zip file using the Python zipfile module

No. Read out the rest of the archive and write it to a new zip file.

Unable to remove zipped file after unzipping

instead of passing in a string to the ZipFile constructor, you can pass it a file like object:

import zipfile
import os

zipped_file = r'D:\test.zip'

with open(zipped_file, mode="r") as file:
zip_file = zipfile.ZipFile(file)
for member in zip_file.namelist():
filename = os.path.basename(member)
if not filename:
continue
source = zip_file.open(member)

os.remove(zipped_file)


Related Topics



Leave a reply



Submit