我找到的唯一从zip文件中删除文件的方法是创建一个没有要删除文件的临时zip文件,然后将其重命名为原始文件名。
在Python 2.4中,ZipInfo类有一个属性file_offset
,因此可以创建第二个zip文件并将数据复制到其他文件而无需解压/重新压缩。
Python 2.6中缺少file_offset
,那么除了通过解压每个文件然后重新压缩它来创建另一个zip文件之外,是否还有其他选择?
也许有一种直接的方法可以删除zip文件中的文件,但我搜索了一下并没有找到任何信息。
我找到的唯一从zip文件中删除文件的方法是创建一个没有要删除文件的临时zip文件,然后将其重命名为原始文件名。
在Python 2.4中,ZipInfo类有一个属性file_offset
,因此可以创建第二个zip文件并将数据复制到其他文件而无需解压/重新压缩。
Python 2.6中缺少file_offset
,那么除了通过解压每个文件然后重新压缩它来创建另一个zip文件之外,是否还有其他选择?
也许有一种直接的方法可以删除zip文件中的文件,但我搜索了一下并没有找到任何信息。
下面的代码片段对我有效(从Zip归档中删除所有*.exe文件):
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 头实际上存储在文件结尾处。我的十六进制编辑器证实了这一点。
因此,你会遇到以下问题:你需要删除主头中的目录条目,否则它将指向一个不存在的文件。如果保留要删除的文件的本地标头,保持主头不变可能会起作用,但我不确定。你以前如何使用旧模块进行操作的?
如果不修改主头,打开时会出现“zipfile 中缺少 X 字节”的错误。 这篇文章 可能会帮助你找出如何修改主头。
虽不太优雅,但这就是我做的方式:
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)
ZipFile
似乎没有删除或更新/替换文件的方法。 - ArtOfWarfarezip
软件。此外,引入了新子进程的开销。 - Buzz基于Elias Zamaria对该问题的评论。
阅读了Python-问题 #51067后,我想对它进行更新。
目前已经有解决方案,但由于作者缺少贡献者协议,因此未被Python批准。
尽管如此,您可以从https://github.com/python/cpython/blob/659eb048cc9cac73c46349eb29845bc5cd630f09/Lib/zipfile.py获取代码,并从中创建一个单独的文件。然后只需从项目中引用该文件而不是内置的Python库:import myproject.zipfile as zipfile
。
使用:
with zipfile.ZipFile(f"archive.zip", "a") as z:
z.remove(f"firstfile.txt")
我相信它将被包含在未来的Python版本中。对于我的使用情况而言,它能够完美地工作。
来自ruamel.std.zipfile
¹的例程delete_from_zip_file
允许您根据ZIP文件中文件的完整路径或基于(re
)模式删除文件。例如,您可以使用以下命令从test.zip
中删除所有.exe
文件:
from ruamel.std.zipfile import delete_from_zip_file
delete_from_zip_file('test.zip', pattern='.*.exe')
*
前面的点号。InMemZipFile()
类在内存中重新创建ZIP文件,在完全读取旧文件后覆盖旧文件。
allowZip64
,不知道它是关于什么的。 - Anthon简而言之:
import zipfile
with zipfile.ZipFile("bad.zip") as bad:
# Or use "a" instead of "w" if you're appending
with zipfile.ZipFile("good", "w") as good:
for zip_info in bad.infolist():
# I had hundreds of duplications of 'sample_100.csv'
not_a_bad_file = zip_info.filename != 'sample_33.csv' or zip_info.file_size > 146622
if not_a_bad_file:
good.writestr(zip_info, bad.read(zip_info))
str
)传递给read
方法,它会给你最后一个项目 - 至少看起来是这样。然而,在阅读CPython代码中的库文档之后,这一部分将变得明显起来。.. note::
The :meth:`.open`, :meth:`read` and :meth:`extract` methods can take a filename
or a :class:`ZipInfo` object. You will appreciate this when trying to read a
ZIP file that contains members with duplicate names.