递归添加文件到压缩档案蟒蛇

问题描述:

在Python 2.7.4在Windows上,如果我有一个目录结构如下:递归添加文件到压缩档案蟒蛇

test/foo/a.bak 
test/foo/b.bak 
test/foo/bar/c.bak 
test/d.bak 

我用的是以下将它们添加到现有存档等'd.bak'位于存档的根目录下:

import zipfile 
import os.path 
import fnmatch 

def find_files(directory, pattern): 
    for root, dirs, files in os.walk(directory): 
     for basename in files: 
      if fnmatch.fnmatch(basename, pattern): 
       filename = os.path.join(root, basename) 
       yield filename 

if __name__=='__main__': 
    z = zipfile.ZipFile("testarch.zip", "a", zipfile.ZIP_DEFLATED) 

    for filename in find_files('test', '*.*'): 
     print 'Found file:', filename 
     z.write(filename, os.path.basename(filename), zipfile.ZIP_DEFLATED) 

    z.close() 

该zip文件的目录是平的。它创建foo/目录只有是否存在在其子目录(如果我排除test/foo/bar/c.bak,它不会创建目录。如果包含,则创建foo/但不foo/bar/如果是有道理的),但没有子目录或文件:

foo/ 
a.bak 
b.bak 
c.bak 
d.bak 

我错过了什么吗?

的问题是,你是明确要求它弄平所有路径:

z.write(filename, os.path.basename(filename), zipfile.ZIP_DEFLATED) 

如果你看一下the docs,默认arcname是:

一样filename,但没有驱动器号并且删除了前导路径分隔符

但是你重写了t与os.path.basename(filename)的帽子。 (如果你不知道什么basename呢,则返回“最后的路径名组成部分。”如果你不想刚刚过去的路径名部分,不叫basename

如果你只是做z.write('test/foo/bar/c.bak'),它将创建一个名为test/foo/bar/c.bak的zip条目,但如果您的确做了z.write('test/foo/bar/c.bak', 'c.bak'),它将创建一个名为c.bak的zip条目。既然你对所有参赛作品都这样做,整个事情就会变得平坦起来。

+0

好吧,我现在看到。有没有办法将'test /'目录的* contents *设置为根目录,而不是目录本身? – nlowe 2013-04-09 01:04:45

+0

我不知道我明白。 'test'的内容是0个或多个文件或目录,并且根必须是一个目录。你的意思是你想'测试'而不是它的父母是根 - 也就是说,你想要的路径相对于''测试/''?这只是'os.path.relpath(路径,'test')'。或者,如果你只想移除第一个组件,你可以将'os.path.split'一直拖到'components'列表,然后'os.path.join(* components [1:])'。 (如果你想要后者,并且需要更多的解释,我可以将它编辑成答案。) – abarnert 2013-04-09 01:33:57

+0

没关系,我想通了。感谢您的帮助! – nlowe 2013-04-09 01:38:00

我想通了。由于abarnet指出,我误解了zip文件上的文档。使用下面的功能,我可以为zip文件创建正确的档案名称:

def createArchName(path): 
    line = path 
    if "\\" in line: 
     ''' windows ''' 
     discard, val = line.split("\\", 1) 
     return val 
    else: 
     ''' unix ''' 
     discard, val = line.split("/", 1) 
     return val 

对于那些有兴趣,完整的代码如下:

import urllib2 
import zipfile 
import os.path 
import fnmatch 

def find_files(directory, pattern): 
    for root, dirs, files in os.walk(directory): 
     for basename in files: 
      if fnmatch.fnmatch(basename, pattern): 
       filename = os.path.join(root, basename) 
       yield filename 

def createArchName(path): 
    line = path 
    if "\\" in line: 
     ''' windows ''' 
     discard, val = line.split("\\", 1) 
     return val 
    else: 
     ''' unix ''' 
     discard, val = line.split("/", 1) 
     return val 


if __name__=='__main__': 
    if not os.path.exists("test"): 
     os.mkdir("test") 

    z = zipfile.ZipFile("testarch.zip", "a", zipfile.ZIP_DEFLATED) 

    for filename in find_files('test', '*.*'): 
     archname = createArchName(filename) 
     print 'Found file:', archname 
     z.write(filename, archname, zipfile.ZIP_DEFLATED) 

    z.close()