我recently asked a question关于如何将大型python对象保存到文件。我以前遇到过将大量Python字典转换为字符串并通过write()
将其写入文件的问题。现在我正在使用泡菜。虽然它有效,但文件非常大(> 5 GB)。我在这么大的文件领域经验不多。我想知道在将这个pickle文件存储到内存之前是否更快,甚至可能将其压缩。
答案 0 :(得分:10)
您可以使用bzip2压缩数据:
from __future__ import with_statement # Only for Python 2.5
import bz2,json,contextlib
hugeData = {'key': {'x': 1, 'y':2}}
with contextlib.closing(bz2.BZ2File('data.json.bz2', 'wb')) as f:
json.dump(hugeData, f)
像这样加载:
from __future__ import with_statement # Only for Python 2.5
import bz2,json,contextlib
with contextlib.closing(bz2.BZ2File('data.json.bz2', 'rb')) as f:
hugeData = json.load(f)
您也可以使用zlib或gzip使用几乎相同的界面压缩数据。但是,zlib和gzip的压缩率都低于用bzip2(或lzma)实现的压缩率。
答案 1 :(得分:3)
在实现数据序列化时,Python代码会非常慢。 如果你尝试在纯Python中创建一个与Pickle等价的东西,你会发现它会超级慢。 幸运的是,执行该功能的内置模块非常好。
除cPickle
外,您会发现marshal
模块,速度要快得多。
但它需要一个真正的文件句柄(而不是来自类文件对象)。
你可以import marshal as Pickle
看看差异。
我不认为你可以制作比这更快的自定义序列化器...
这是一个实际的(不是那么老)serious benchmark of Python serializers
答案 2 :(得分:1)
更快,甚至可能在[写作]之前压缩这个pickle文件
当然有可能,但没有理由在写入之前尝试在内存中创建一个显式的压缩副本(它可能不适合!),当你可以自动使其在写入时被压缩,具有内置标准库功能;)
见http://docs.python.org/library/gzip.html。基本上,您使用
创建一种特殊的流gzip.GzipFile("output file name", "wb")
然后使用它就像使用file
(或open(...)
创建的普通file(...)
一样使用它。
答案 3 :(得分:1)
我只是扩展phihag的答案。
当尝试序列化接近RAM大小的对象时,应该避免使用 pickle / cPickle ,因为它requires additional memory of 1-2 times the size of the object是为了序列化。即使将其流式传输到BZ2File也是如此。在我的情况下,我甚至用完了交换空间。
但是JSON的问题(以及与链接文章中提到的HDF文件类似)是它无法序列化元组,这些元组在我的数据中被用作dicts的键。对此没有很好的解决方案;我能找到的最好的方法是将元组转换为字符串,这需要一些自己的内存,但要比pickle少得多。如今,您还可以使用the ujson library,这比json库快得多。
对于由字符串组成的元组(要求字符串不包含逗号):
import ujson as json
from bz2 import BZ2File
bigdata = { ('a','b','c') : 25, ('d','e') : 13 }
bigdata = dict([(','.join(k), v) for k, v in bigdata.viewitems()])
f = BZ2File('filename.json.bz2',mode='wb')
json.dump(bigdata,f)
f.close()
重新组合元组:
bigdata = dict([(tuple(k.split(',')),v) for k,v in bigdata.viewitems()])
或者,例如,你的键是2元组的整数:
bigdata2 = { (1,2): 1.2, (2,3): 3.4}
bigdata2 = dict([('%d,%d' % k, v) for k, v in bigdata2.viewitems()])
# ... save, load ...
bigdata2 = dict([(tuple(map(int,k.split(','))),v) for k,v in bigdata2.viewitems()])
这种方法相对于泡菜的另一个优点是,当使用bzip2压缩时,json似乎比泡菜更好地压缩。
答案 4 :(得分:-1)
查看Google的ProtoBuffers。虽然它们并非设计用于开箱即用的大型文件,如音频 - 视频文件,但它们可以很好地处理对象序列化,因为它们是为它设计的。实践表明,有一天您可能需要更新文件的结构,ProtoBuffers将处理它。此外,它们还针对压缩和速度进行了高度优化。而且你并没有依赖Python,Java和C ++得到很好的支持。