Python 2.6 не любит добавлять существующие архивы в zip-файлы - PullRequest
5 голосов
/ 27 мая 2010

В некоторых модульных тестах Python для программы, над которой я работаю, мы используем zip-файлы в памяти для сквозных тестов. В SetUp () мы создаем простой zip-файл, но в некоторых тестах мы хотим перезаписать некоторые архивы. Для этого мы делаем «zip.writestr (имя_архива, zip.read (имя_архива) + 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 »отличаются.»

Кажется, что он читает правильную панель файлов, но думает, что вместо этого он должен читать foo.

Я в растерянности. Что я делаю неправильно? Это не поддерживается? Я попытался найти в Интернете, но не нашел упоминаний о похожих проблемах. Я прочитал документацию по zipfile, но не смог найти ничего (что мне показалось) соответствующим, тем более что я вызываю read () со строкой имени файла.

Есть идеи?

Заранее спасибо!

Ответы [ 2 ]

2 голосов
/ 27 мая 2010

Файл 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 'обычно не читается и, безусловно, должен искать () ed между чтением и записью. Я собираюсь дурачиться и обновлять это.

Обновление:

Украдя почти весь этот код из превосходного Python-модуля недели Дуга Хеллмана , я обнаружил, что он работает почти так, как я ожидал. Нельзя просто добавить к структурированному файлу 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

Он не добавлялся к существующему имени дуги 'hosts', он создал дополнительного члена архива.

"Je n'ai fait celle-ci plus longue que Parce Que Je N'ai Pas EU Le Loisir де la faire plus courte. "
- Блез Паскаль

0 голосов
/ 21 июня 2016

Формат файла 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
...