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

5

我在使用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"不一致。

更新:我用临时文件(tempfile.mkstemp("temp.zip"))替换了字符串缓存cStringIO.StringIO(),现在它可以工作了。当zipfile模块写入缓存时会发生某些事情导致归档文件损坏,但我不确定问题出在哪里。

问题是我读取/写入的文件以"r"/"w"模式打开而不是"rb"/"wb"模式。在Linux中这不是问题,但由于字符编码问题,在Windows中它给我带来错误。现已解决。


我只是举了这些作为例子,路径已经正确形成,使用转义反斜杠('C:\path\to\folder')。然而,没有一个回复回答了这个问题。异常信息是“zipfile.BadZipfile: File name in directory "env\index" and header "env/index" differ." - Cat
2
+1 支持反对随意、无解释的负评。 - jedwards
我更新了我的答案 —— 这应该解决了你的问题。 - jedwards
如果使用 zf.write(os.path.join(dirname, filename)) 会发生什么? - Velociraptors
如果我不给write函数第二个参数,它会在存档中构建整个目录结构,而这并不是我需要的。例如,它会生成useless\\directory\\structure\\up\\to\\relevant\\directory而不是relevant\\directory。我认为这个问题与cStringIO.StringIO()有关。 - Cat
当您编辑原始帖子以反映更改时,应该确实保留您的“错误”代码,以便未来遇到此类问题的人可以找到相关答案。 - jedwards
4个回答

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的错误,它可能会被忽视。(请参见Issue 6839)。

4
我在这里找到了我的问题的答案:http://www.penzilla.net/tutorials/python/scripting
我粘贴了与压缩目录相关的两个函数。问题不在于字符串缓冲区,也不在于斜线,而是我遍历并向zipfile写入的方式。这两个递归函数解决了问题。使用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!"

1

你需要转义路径中的反斜杠。

尝试更改以下内容:

  • the_path= "C:\path\to\folder"the_path = "C:\\path\\to\\folder",以及
  • zf.extractall("C:\destination\path")zf.extractall("C:\\destination\\path")

1
您可以使用正斜杠作为路径分隔符,即使在Windows上也是如此。我建议您在创建zip文件时尝试使用这种方法。

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