2010-05-27 76 views
5

在我正在研究的程序的某些Python單元測試中,我們使用內存中的zip文件進行端到端測試。在SetUp()中,我們創建了一個簡單的zip文件,但在一些測試中,我們想覆蓋一些存檔。爲此,我們執行「zip.writestr(archive_name,zip.read(archive_name)+ new_content)」。像Python 2.6不喜歡附加到zip文件中的現有檔案

import zipfile 
from StringIO import StringIO 

def Foo(): 
    zfile = StringIO() 
    zip = zipfile.ZipFile(zfile, 'a') 
    zip.writestr(
     "foo", 
     "foo content") 
    zip.writestr(
     "bar", 
     "bar content") 
    zip.writestr(
     "foo", 
     zip.read("foo") + 
     "some more foo content") 
    print zip.read("bar") 

Foo() 

問題的東西是,這部作品在Python 2.4和2.5罰款,但不2.6。在Python 2.6中,在打印行中「BadZipfile:目錄中的文件名」欄和「foo」標題不同。

它似乎正在讀取正確的文件欄,但它認爲它應該讀取foo。

我不知所措。我究竟做錯了什麼?這不支持?我試圖搜索網頁,但可能找不到類似的問題。我讀了zipfile文檔,但找不到任何東西(我認爲是)相關的,特別是因爲我用文件名字符串調用read()。

任何想法?

預先感謝您!

回答

2

該PKZIP文件是高度結構化的,只是追加到最後會把它搞砸了。我不能說早期版本的工作,但解決這個問題的方法是打開一個zip文件進行閱讀,打開一個新的文件,提取第一個文件的內容,然後在最後添加你的添加組件。完成後,用新創建的文件替換原始的zip文件。

運行代碼時運行代碼時我得到的回溯是:

Traceback (most recent call last): 
    File "zip.py", line 19, in <module> 
    Foo() 
    File "zip.py", line 17, in Foo 
    print zip.read("bar") 
    File "/usr/lib/python2.6/zipfile.py", line 834, in read 
    return self.open(name, "r", pwd).read() 
    File "/usr/lib/python2.6/zipfile.py", line 874, in open 
    zinfo.orig_filename, fname) 
zipfile.BadZipfile: File name in directory "bar" and header "foo" differ. 

經仔細檢查,我注意到,你從一個類文件StringIO的閱讀與「a'ppend模式打開它應該導致讀取錯誤,因爲'a'通常不可讀,並且當然必須在讀取和寫入之間尋找()。我會欺騙一些並更新它。

更新:

偷了幾乎所有從道格·赫爾曼的優秀Python Module of the Week這個代碼,我發現它的作品如我所料相當多。人們不能僅僅附加到一個結構化的PKZIP文件,如果在原來的職位代碼做過的工作,這是意外:

import zipfile 
import datetime 

def create(archive_name): 
    print 'creating archive' 
    zf = zipfile.ZipFile(archive_name, mode='w') 
    try: 
     zf.write('/etc/services', arcname='services') 
    finally: 
     zf.close() 

def print_info(archive_name): 
    zf = zipfile.ZipFile(archive_name) 
    for info in zf.infolist(): 
     print info.filename 
     print '\tComment:\t', info.comment 
     print '\tModified:\t', datetime.datetime(*info.date_time) 
     print '\tSystem:\t\t', info.create_system, '(0 = Windows, 3 = Unix)' 
     print '\tZIP version:\t', info.create_version 
     print '\tCompressed:\t', info.compress_size, 'bytes' 
     print '\tUncompressed:\t', info.file_size, 'bytes' 
     print 
    zf.close() 

def append(archive_name): 
    print 'appending archive' 
    zf = zipfile.ZipFile(archive_name, mode='a') 
    try: 
     zf.write('/etc/hosts', arcname='hosts') 
    finally: 
     zf.close() 

def expand_hosts(archive_name): 
    print 'expanding hosts' 
    zf = zipfile.ZipFile(archive_name, mode='r') 
    try: 
     host_contents = zf.read('hosts') 
    finally: 
     zf.close 

    zf = zipfile.ZipFile(archive_name, mode='a') 
    try: 
     zf.writestr('hosts', host_contents + '\n# hi mom!') 
    finally: 
     zf.close() 

def main(): 
    archive = 'zipfile.zip' 
    create(archive) 
    print_info(archive) 
    append(archive) 
    print_info(archive) 
    expand_hosts(archive) 
    print_info(archive) 

if __name__ == '__main__': main() 

值得注意的是,從上一次調用輸出到print_info

... 
hosts 
    Modified: 2010-05-20 03:40:24 
    Compressed: 404 bytes 
    Uncompressed: 404 bytes 

hosts 
    Modified: 2010-05-27 11:46:28 
    Compressed: 414 bytes 
    Uncompressed: 414 bytes 

它沒有附加到現有的arcname'hosts',它創建了一個額外的存檔成員。

「濟n'ai既成事實勒慈加椅闕 parce闕乙腦n'ai PAS歐盟樂德羅伊薩拉 放任加courte。」
- 帕斯卡

0

ZIP文件格式被設計成被附加到。它可以添加具有相同名稱的其他文件,並提取最後一個文件,但ZipFile不能同時讀寫。您必須關閉該文件以寫出最終記錄(https://hg.python.org/cpython/file/2.7/Lib/zipfile.py#l1263),然後再通過open()read()方法讀入。 (https://hg.python.org/cpython/file/2.7/Lib/zipfile.py#l933

import zipfile 
from StringIO import StringIO 

def Foo(): 
    zfile = StringIO() 

    zip = zipfile.ZipFile(zfile, 'a') 
    zip.writestr(
     "foo", 
     "foo content") 
    zip.writestr(
     "bar", 
     "bar content") 
    zip.close() 

    zip = zipfile.ZipFile(zfile, 'r') 
    foo_content = zip.read("foo") 

    zip2 = zipfile.ZipFile(zfile, 'a') 
    zip2.writestr(
     "foo", 
     foo_content + 
     "some more foo content") 
    print zip2.namelist() 
    print zip2.read("bar") 

Foo() 

輸出:

pyzip.py:23: UserWarning: Duplicate name: 'foo' 
    "some more foo content") 
['foo', 'bar', 'foo'] 
bar content