Загрузить файл рассола из 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, не являются обязательными ограничениями в вашем приложении).