Python的zipfile模块无法更新条目

4 投票
2 回答
1519 浏览
提问于 2025-04-17 16:25

我想用Python的zipfile模块来更新一个压缩文件里的内容。我的问题是,这样做会生成一个新的条目。

假设我有以下这段代码:

from zipfile import ZipFile,ZIP_DEFLATED
with ZipFile("myfile.zip","w") as z:
    z.writestr("hello.txt", "the content of hello.txt", ZIP_DEFLATED)
    ###  how to update the hello.txt file here ?
    z.writestr("hello.txt", "the content of hello.txt", ZIP_DEFLATED)

执行完这段代码后,压缩文件里会有两个条目,而不是一个:

$ unzip -l myfile.zip 
Archive:  myfile.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
       24  2013-02-19 22:48   hello.txt
       24  2013-02-19 22:48   hello.txt
---------                     -------
       48                     2 files
$ python --version
Python 3.3.0
$

我知道可以写一个全新的文件,但如果内容很大,这样做会花费很多时间。

其实,zip(1)这个工具可以做到这一点(使用“-u”选项),那为什么Python做不到呢?有没有办法用Python实现这个功能呢?

2 个回答

0

我觉得 zipfile 这个模块可能无法像你想的那样修改压缩文件。如果可以的话,它应该会有一个可以从 ZipFile 中删除文件的方法,但实际上并没有这个方法。

6

zip格式没有简单的方法来删除或替换压缩包里的文件。可能有一些库可以做到这一点,但我不知道具体有哪些。

不过等等:

zip(1)工具可以做到这一点(使用“-u”选项),那为什么Python不能呢?

其实,-u的作用只是告诉它“只有在文件时间戳不更新的情况下才替换已有文件”,这在这里并不重要。如果不加-u,默认命令是add,它会做同样的事情,但不检查时间戳:

更新已有的条目并添加新文件。如果压缩包不存在,就创建一个。这是默认模式。

更重要的是,正如你提到的手册页明确指出:

Zip文件。当修改一个已有的zip压缩包时,zip会先写一个临时文件,里面是新内容,只有在新版本创建完成且没有错误时,才会替换掉旧的文件。

这正是你想做的:先把完整的新文件写到一个临时位置,然后再用新文件替换掉原来的文件。

如果你需要在Windows上实现,这可能会有点麻烦。(如果不需要,就直接使用tempfile.NamedTemporaryFileos.rename。)但你已经知道怎么做了:

我知道如何写一个完整的新文件,但如果内容很大,这会花很多时间。

其实这和zip -u花的时间差不多。

撰写回答