Загрузить файл рассола из zipfile

По какой-то причине я не могу заставить cPickle.load работать с объектом типа файла, возвращаемого ZipFile.open(). Если я вызываю read() для объекта типа файла, возвращаемого ZipFile.open (), я могу использовать cPickle.loads.

Пример....

import zipfile
import cPickle

# the data we want to store
some_data = {1: 'one', 2: 'two', 3: 'three'}

#
# create a zipped pickle file
#
zf = zipfile.ZipFile('zipped_pickle.zip', 'w', zipfile.ZIP_DEFLATED)
zf.writestr('data.pkl', cPickle.dumps(some_data))
zf.close()

#
# cPickle.loads works
#
zf = zipfile.ZipFile('zipped_pickle.zip', 'r')
sd1 = cPickle.loads(zf.open('data.pkl').read())
zf.close()

#
# cPickle.load doesn't work
#
zf = zipfile.ZipFile('zipped_pickle.zip', 'r')
sd2 = cPickle.load(zf.open('data.pkl'))
zf.close()

Примечание: я не хочу архивировать только файл pickle, но много файлов других типов. Это всего лишь пример.

1 ответ

Это связано с несовершенством объекта псевдофайла, реализованного zipfile модуль (для .open метод ZipFile класс введен в Python 2.6). Рассматривать:

>>> f = zf.open('data.pkl')
>>> f.read(1)
'('
>>> f.readline()
'dp1\n'
>>> f.read(1)
''
>>> 

последовательность .read(1) - .readline() это что .loads внутренне это делает (при использовании протокола 0, по умолчанию в Python 2, который вы здесь используете). к несчастью zipfile Несовершенство означает, что эта конкретная последовательность не работает, создавая ложный "конец файла" (.read, возвращающий пустую строку) сразу после первой пары read/readline.

Не уверен, что эта ошибка в стандартной библиотеке Python исправлена ​​в Python 2.7 - я собираюсь проверить.

Изменить: только что проверил - ошибка исправлена ​​в Python 2.7 rc1 (кандидат на выпуск, который в настоящее время является последней версией 2.7). Я пока не знаю, исправлено ли это в последней версии исправления ошибок версии 2.6.

Отредактируйте еще раз: ошибка все еще существует в Python 2.6.5, последней версии исправления ошибок Python 2.6 - так что, если вы не можете перейти на 2.7 и вам нужны объекты псевдофайла с лучшим поведением из ZipFile.open бэкпорт исправления 2.7 кажется единственным жизнеспособным решением.

Обратите внимание, что вы не уверены, что вам нужны объекты с псевдофайлами с лучшим поведением; если вы управляете вызовами дампа и можете использовать новейший протокол, все будет хорошо:

>>> zf = zipfile.ZipFile('zipped_pickle.zip', 'w', zipfile.ZIP_DEFLATED)
>>> zf.writestr('data.pkl', cPickle.dumps(some_data, -1))
>>> sd2 = cPickle.load(zf.open('data.pkl'))
>>> 

это только старый грубый обратно-совместимый "протокол 0" (по умолчанию), который требует правильного поведения объекта псевдофайла при смешивании вызовов read и readline в load (протокол 0 также работает медленнее и приводит к увеличению числа солений, поэтому он определенно не рекомендуется, если только обратная совместимость со старыми версиями Python или характер только для ascii свойств, которые генерирует 0, не являются обязательными ограничениями в вашем приложении).

Другие вопросы по тегам