在Windows上的Python 2.7.4中,如果我有一个目录结构:
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
我错过了什么吗?
答案 0 :(得分:2)
问题在于你明确要求它展平所有路径:
z.write(filename, os.path.basename(filename), zipfile.ZIP_DEFLATED)
如果您查看the docs,则默认arcname
为:
与
filename
相同,但没有驱动器号并删除了前导路径分隔符
但是你用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条目。因为你为所有条目都这样做,所以整个事情最终变平了。
答案 1 :(得分:0)
我明白了。正如 abarnet 指出的那样,我误读了zipfiles上的文档。使用以下函数,我可以为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()