5

私が取り組んでいるプログラムの一部の Python ユニット テストでは、エンド ツー エンドのテストにインメモリ zip ファイルを使用します。SetUp() では単純な zip ファイルを作成しますが、いくつかのテストではいくつかのアーカイブを上書きしたいと考えています。このために、「zip.writestr(archive_name, zip.read(archive_name) + new_content)」を実行します。何かのようなもの

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: ディレクトリ "bar" のファイル名とヘッダー "foo" が異なります。」で失敗します。

正しいファイル bar を読み取っているように見えますが、代わりに foo を読み取る必要があると考えています。

私は途方に暮れています。私は何を間違っていますか?これはサポートされていませんか? Web を検索してみましたが、同様の問題に関する言及は見つかりませんでした。zipfile のドキュメントを読みましたが、特にファイル名の文字列で read() を呼び出しているため、関連するもの (と思われるもの) を見つけることができませんでした。

何か案は?

前もって感謝します!

4

2 に答える 2

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.

よく調べてみると、「a」は一般に読み取り可能ではないため、「a」追加モードで開かれたファイルのような StringIO から読み取っていることに気付きました。書いています。私はいくつかをだまして、これを更新するつもりです。

アップデート:

このコードのほとんどすべてを Doug Hellmann の優れた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' に追加されず、追加のアーカイブ メンバーが作成されました。

「Je n'ai fait celle-ci plus longue que parce que je n'ai pas eu le loisir de la faire plus courte.」
-ブレーズ・パスカル

于 2010-05-27T14:56:05.420 に答える