递归添加文件到压缩档案蟒蛇
问题描述:
在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条目。既然你对所有参赛作品都这样做,整个事情就会变得平坦起来。
答
我想通了。由于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()
好吧,我现在看到。有没有办法将'test /'目录的* contents *设置为根目录,而不是目录本身? – nlowe 2013-04-09 01:04:45
我不知道我明白。 'test'的内容是0个或多个文件或目录,并且根必须是一个目录。你的意思是你想'测试'而不是它的父母是根 - 也就是说,你想要的路径相对于''测试/''?这只是'os.path.relpath(路径,'test')'。或者,如果你只想移除第一个组件,你可以将'os.path.split'一直拖到'components'列表,然后'os.path.join(* components [1:])'。 (如果你想要后者,并且需要更多的解释,我可以将它编辑成答案。) – abarnert 2013-04-09 01:33:57
没关系,我想通了。感谢您的帮助! – nlowe 2013-04-09 01:38:00