无法解压使用zipfile构建的归档文件(Python)

5 投票
4 回答
5817 浏览
提问于 2025-04-16 17:59

我在用Python的zipfile模块创建一个压缩文件时遇到了问题。我在一个文件夹里遍历所有文件,然后把它们写入压缩文件。可是当我尝试提取这些文件时,出现了一个和路径分隔符有关的错误。

the_path= "C:\\path\\to\\folder"
zipped= cStringIO.StringIO()
zf = zipfile.ZipFile(zipped_cache, "w", zipfile.ZIP_DEFLATED)
for dirname, subdirs, files in os.walk(the_path) :
    for filename in files:
        zf.write(os.path.join(dirname, filename), os.path.join(dirname[1+len(the_path):], filename))
zf.extractall("C:\\destination\\path")
zf.close()
zipped_cache.close()

这是我遇到的错误信息:

zipfile.BadZipfile: 目录中的文件名 "env\index" 和头部中的 "env/index" 不同。

更新:我把字符串缓冲区 cStringIO.StringIO() 替换成了一个临时文件 (tempfile.mkstemp("temp.zip")),现在可以正常工作了。zipfile模块在写入缓冲区时会出现一些问题,导致压缩文件损坏,但我不太确定具体是什么问题。

问题在于我在读写文件时使用了 "r"/"w" 模式,而不是 "rb"/"wb" 模式。在Linux上这没问题,但在Windows上因为字符编码的原因就出错了。现在解决了。

4 个回答

1

你可以使用正斜杠(/)作为路径分隔符,即使是在Windows系统上也可以。我建议你在创建压缩文件的时候试试这个方法。

5

你应该在字符串前面加一个r,这样可以告诉程序这是一个原始字符串——路径中的反斜杠会被当作转义字符来处理。

下面的代码:

#!/bin/env python    
print(r"C:\destination\path")
print(r"C:\path\to\folder")
print("C:\destination\path")
print("C:\path\to\folder")

会产生以下输出:

C:\destination\path
C:\path\to\folder
C:\destination\path
C:\path o
         older

注意最后一行中的 \t 和 \f 被解释成了制表符换页符

有趣的是,你也可以把反斜杠换成正斜杠(也就是 open("C:/path/to/folder")),这样也是可以的。

或者,你可以用反斜杠来转义反斜杠(也就是 open("C:\\path\\to\\folder"))。

在我看来,最简单明了的办法就是直接加一个r


编辑:
看起来你需要选择第二种方案,使用正斜杠。zipfile库似乎有点严格——而且因为这是一个仅限Windows的bug,可能是悄悄溜过来的。(参见 问题6839。)

4

我在这里找到了我问题的答案:http://www.penzilla.net/tutorials/python/scripting

我把两个和压缩目录相关的函数贴出来。问题不在于字符串缓冲区,也不是斜杠,而是我在遍历和写入压缩文件时的方法。这两个递归函数解决了这个问题。用os.walk遍历整个子目录树并不是写归档文件的好方法。

def zippy(path, archive):
    paths = os.listdir(path)
    for p in paths:
        p = os.path.join(path, p) # Make the path relative
        if os.path.isdir(p): # Recursive case
            zippy(p, archive)
        else:
            archive.write(p) # Write the file to the zipfile
    return

def zipit(path, archname):
    # Create a ZipFile Object primed to write
    archive = ZipFile(archname, "w", ZIP_DEFLATED) # "a" to append, "r" to read
    # Recurse or not, depending on what path is
    if os.path.isdir(path):
        zippy(path, archive)
    else:
        archive.write(path)
    archive.close()
    return "Compression of \""+path+"\" was successful!"

撰写回答