簡體   English   中英

在Python中存儲大文件的最快方法

[英]Fastest way to store large files in Python

最近問了一個關於如何將大型python對象保存到文件的問題。 我以前遇到過將大量Python字典轉換為字符串並通過write()將它們write()文件的問題。 現在我正在使用泡菜。 雖然它可以工作,但文件非常大(> 5 GB)。 我在這么大的文件領域經驗不多。 我想知道在將這個pickle文件存儲到內存之前是否更快,甚至可能將其壓縮。

您可以使用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)

您也可以使用zlibgzip壓縮數據,使用幾乎相同的界面。 但是,zlib和gzip的壓縮率都低於用bzip2(或lzma)實現的壓縮率。

在實現數據序列化時,Python代碼會非常慢。 如果你嘗試在純Python中創建一個與Pickle等價的東西,你會發現它會超級慢。 幸運的是,執行該功能的內置模塊非常好。

除了cPickle之外,你會發現marshal模塊,速度要快得多。 但它需要一個真正的文件句柄(而不是來自類文件對象)。 您可以import marshal as Pickle並查看差異。 我不認為你可以制作比這更快的自定義序列化器......

是Python序列化程序的實際(不是那么老) 嚴肅的基准

我只想擴展phihag的答案。

當嘗試序列化接近RAM大小的對象時, 應該避免使用pickle / cPickle ,因為它需要額外的內存,大小是對象大小的1-2倍才能序列化。 即使將其流式傳輸到BZ2File也是如此。 在我的情況下,我甚至耗盡了交換空間。

但是JSON的問題(以及與鏈接文章中提到的HDF文件類似)是它無法序列化元組,這在我的數據中用作dicts的鍵。 對此沒有很好的解決方案; 我能找到的最好的方法是將元組轉換為字符串,這需要一些自己的內存,但要比pickle少得多。 如今,您還可以使用ujson庫 ,它比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似乎比泡菜更好地壓縮。

更快,甚至可能在[寫作]之前壓縮這個pickle文件

當然這是可能的,但沒有理由在編寫它之前嘗試在內存中創建一個顯式的壓縮副本(它可能不適合!),當你​​可以自動使它在編寫時壓縮,內置標准庫功能 ;)

http://docs.python.org/library/gzip.html 基本上,你用它創建一種特殊的流

gzip.GzipFile("output file name", "wb")

然后使用它就像使用open(...) (或file(...)創建的普通file一樣)。

看看谷歌的ProtoBuffers 雖然它們並非設計用於開箱即用的大型文件,如音頻 - 視頻文件,但它們可以很好地處理對象序列化,因為它們是為它設計的。 實踐表明,有一天您可能需要更新文件的結構,ProtoBuffers將處理它。 此外,它們還針對壓縮和速度進行了高度優化。 而且你不依賴於Python,Java和C ++都得到了很好的支持。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM