2013-04-09 62 views
0

在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 

我錯過了什麼嗎?

回答

2

的問題是,你是明確要求它弄平所有路徑:

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

0

我想通了。由於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()