загрузить файл рассола из zipfile - PullRequest
5 голосов
/ 09 июня 2010

По какой-то причине я не могу заставить 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()

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

1 Ответ

8 голосов
/ 09 июня 2010

Это связано с несовершенством объекта псевдофайла, реализованного модулем 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.

Not sure offhandесли эта ошибка в стандартной библиотеке Python исправлена ​​в Python 2.7 - я собираюсь проверить.

Edit : только что проверил - ошибка исправлена ​​в 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 также медленнее и приводит к большим значениям pickles, поэтому это определенно не рекомендуется, если только обратная совместимость со старыми версиями Python или характер только для ascii, не равны 0производит, являются обязательными ограничениями в вашем приложении).

...