代码之家  ›  专栏  ›  技术社区  ›  eric.frederich

从压缩文件加载pickle文件

  •  4
  • eric.frederich  · 技术社区  · 15 年前

    由于某些原因,我无法让cpickle.load处理zipfile.open()返回的文件类型对象。 如果我对zipfile.open()返回的文件类型对象调用read(),那么我可以使用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 回复  |  直到 15 年前
        1
  •  7
  •   Alex Martelli    15 年前

    这是由于伪文件对象中由 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 pickle上,这是python 2中的默认值,您在这里使用的就是这个值)。不幸地 压缩文件 '的不完美意味着这个特殊的序列不起作用,在第一个读/读行对之后产生一个虚假的“文件结束”(.read返回空字符串)。

    如果在Python2.7中修复了Python标准库中的这个bug,现在还不确定——我要检查一下。

    编辑 :刚刚检查过——这个bug在python 2.7rc1中得到修复(这个版本的候选版本目前是最新的2.7版本)。我还不知道它是否在2.6最新的bug修复版本中得到了修复。

    再次编辑 :python 2.6.5是python 2.6最新的bug修复版本,但这个bug仍然存在,所以如果您不能升级到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”(默认值)在混合读取和读取行调用时需要正确的伪文件对象行为。 load (协议0速度也较慢,会导致较大的pickle,因此绝对不建议这样做,除非与旧的python版本向后兼容,或者0生成的pickle的ASCII唯一性质是应用程序中的强制约束)。