2010-05-27 49 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