在Python中如何指定zip文件的压缩级别?

3

我该如何在Python中压缩文件并指定压缩级别?

目前我有以下代码,但我遇到了错误:

Zip("log4j.dl-service.log.2013-05-03-22",9)
AttributeError: 'str' object has no attribute 'ZipFile'

代码:

import zipfile
import fileinput

def Zip(file,level):
    """
    This function uses the zip library native to python to compress files with
    Usage: Zip(file,level)
    """

    if file and level:
        try:
            zipfile = file+'.zip'
            output = zipfile.ZipFile(zipfile, 'wb')
            for line in fileinput.input(file):
                output.write(line)
            output.close()
            if os.path.exists(zipfile):
                return zipfile
            else:
                logMe('critical',"zip failed in Zip()")
                return False

        except Exception,e:
            logMe('critical',e)

7
A: 不要使用与您的导入相同的变量名称,那只会带来麻烦。 B: 不要使用与您的导入相同的变量名称,这使得代码难以阅读。 C: 不要使用与您的导入相同的变量名称。 - Jeff Langemeier
@JeffLangemeier:你应该将其作为一个答案写下来(附上更多信息),因为... 嗯,那就是答案。 - abarnert
1
@SimplySeth:请发布完整的回溯信息,而不仅仅是错误消息。在这种情况下,我们可以很容易地猜出问题所在,因为只有一个地方尝试访问名为 ZipFile 的属性,但为什么要让我们猜测呢? - abarnert
2个回答

10
这里的问题在于这行代码:
zipfile = file+'.zip'

在那之后,zipfile不再指向模块,而是指向这个字符串。因此,当你执行以下操作时:

output = zipfile.ZipFile(zipfile, 'wb')

你正在请求一个字符串调用 ZipFile,而不是一个模块。
因此出现了这个错误:
AttributeError: 'str' object has no attribute 'ZipFile'

不要将您的变量命名为zipfile即可解决问题。正如Jeff Langemeier所说,关键在于:不要使用与导入相同的变量名称,这只会带来麻烦。更一般地说,不要给两个不同的事物起相同的名称。引用他的话来说就是:“A: 不要使用与导入相同的变量名称,这只会带来麻烦。B: 不要使用与导入相同的变量名称,这使得代码难以阅读。C: 不要使用与导入相同的变量名称。”。
针对您的第二个问题:
如何指定压缩等级?
您不能这样做。 这是有意的,原因与命令行工具 zip 不再记录 10 个压缩级别一样,只有存储(无压缩)和“更好压缩”(-9)。 几乎从来没有任何除了存储或默认之外的好用途。 -9 常常并不比默认的压缩更好——或者它对某些文件进行更好的压缩,而对其他文件进行更差的压缩。 如果您需要更好的压缩,则需要更好的算法——例如,使用.tar.bz2 而不是 .zip,或者使用 p7zip(可以创建 zip 兼容的文件),而不是普通的 zip。
因此,Python 库只给您两个选择:存储或默认。正如文档所示:

class zipfile.ZipFile(file[, mode[, compression[, allowZip64]]])

...

compression是在写入归档文件时使用的ZIP压缩方法,应为ZIP_STORED或ZIP_DEFLATED。

对于writewritestr方法也是如此。

如果你真的想这么做,可以直接调用zlib.compress,直接创建一个ZipInfo对象,并将其添加到归档文件中。如果你查看源代码(链接在文档中),你可以看到writestr的实现——一旦剔除所有无关的条件和类型检查,它其实并不复杂。

但实际上,我认为你不想这么做。


我只是添加了这个,因为我以为 @JeffLangemeier 不会回答。我本来想删除它的,但现在它已经被投票两次了。我想这提供了一些额外的解释,但 Jeff 先找到了问题并提供了答案。 - abarnert
就我个人而言,我更喜欢你的回答,我无法像你那样清晰地表达出来。 - Jeff Langemeier
@JeffLangemeier:我认为“不要使用与您的导入相同的变量名”非常清晰。而且我喜欢重复,每次都有不同的原因。 - abarnert
1
我猜我现在要成为“博士苏斯式的搏击俱乐部”回答者了。 - Jeff Langemeier
显然我的大脑出现了故障,因为我在文档中找不到设置压缩级别(1-9)的位置。 - Simply Seth
显示剩余2条评论

7
所以,我想我的评论也是答案。
你的变量实质上是对导入方法调用的"过载",这会造成代码非常糟糕的混乱。所以请遵循以下规则:
A: 不要使用与导入相同的变量名,这只会带来麻烦。
B: 不要使用与导入相同的变量名,这使得代码无法阅读。
C: 不要使用与导入相同的变量名。
如果你遵循这些规则,将为你和你询问的人节省很多头疼。如果你确实选择让它接近,使用下划线来分隔zip_file,filezip或任何其他东西即可。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接