Có vẻ như bạn đang uống một chút dưa chua! ;-). Hy vọng rằng sau này, bạn sẽ KHÔNG BAO GIỜ SỬ DỤNG PICKLE EVER. Nó không chỉ là một định dạng lưu trữ dữ liệu rất tốt.
Anyways, cho câu trả lời này, tôi giả định lớp học Document
của bạn trông hơi giống thế này.Nếu không, bình luận với lớp Document
thực tế của bạn:
class Document(object): # <-- object part is very important! If it's not there, the format is different!
def __init__(self, title, date, text): # assuming all strings
self.title = title
self.date = date
self.text = text
Anyways, tôi thực hiện một số dữ liệu thử nghiệm đơn giản với lớp này:
d = [Document(title='foo', text='foo is good', date='1/1/1'), Document(title='bar', text='bar is better', date='2/2/2'), Document(title='baz', text='no one likes baz :(', date='3/3/3')]
muối nó với định dạng 2
(pickle.HIGHEST_PROTOCOL
cho Python 2.x)
>>> s = pickle.dumps(d, 2)
>>> s
'\x80\x02]q\x00(c__main__\nDocument\nq\x01)\x81q\x02}q\x03(U\x04dateq\x04U\x051/1/1q\x05U\x04textq\x06U\x0bfoo is goodq\x07U\x05titleq\x08U\x03fooq\tubh\x01)\x81q\n}q\x0b(h\x04U\x052/2/2q\x0ch\x06U\rbar is betterq\rh\x08U\x03barq\x0eubh\x01)\x81q\x0f}q\x10(h\x04U\x053/3/3q\x11h\x06U\x13no one likes baz :(q\x12h\x08U\x03bazq\x13ube.'
Và tháo rời nó với pickletools
:
>>> pickletools.dis(s)
0: \x80 PROTO 2
2: ] EMPTY_LIST
3: q BINPUT 0
5: ( MARK
6: c GLOBAL '__main__ Document'
25: q BINPUT 1
27:) EMPTY_TUPLE
28: \x81 NEWOBJ
29: q BINPUT 2
31: } EMPTY_DICT
32: q BINPUT 3
34: ( MARK
35: U SHORT_BINSTRING 'date'
41: q BINPUT 4
43: U SHORT_BINSTRING '1/1/1'
50: q BINPUT 5
52: U SHORT_BINSTRING 'text'
58: q BINPUT 6
60: U SHORT_BINSTRING 'foo is good'
73: q BINPUT 7
75: U SHORT_BINSTRING 'title'
82: q BINPUT 8
84: U SHORT_BINSTRING 'foo'
89: q BINPUT 9
91: u SETITEMS (MARK at 34)
92: b BUILD
93: h BINGET 1
95:) EMPTY_TUPLE
96: \x81 NEWOBJ
97: q BINPUT 10
99: } EMPTY_DICT
100: q BINPUT 11
102: ( MARK
103: h BINGET 4
105: U SHORT_BINSTRING '2/2/2'
112: q BINPUT 12
114: h BINGET 6
116: U SHORT_BINSTRING 'bar is better'
131: q BINPUT 13
133: h BINGET 8
135: U SHORT_BINSTRING 'bar'
140: q BINPUT 14
142: u SETITEMS (MARK at 102)
143: b BUILD
144: h BINGET 1
146:) EMPTY_TUPLE
147: \x81 NEWOBJ
148: q BINPUT 15
150: } EMPTY_DICT
151: q BINPUT 16
153: ( MARK
154: h BINGET 4
156: U SHORT_BINSTRING '3/3/3'
163: q BINPUT 17
165: h BINGET 6
167: U SHORT_BINSTRING 'no one likes baz :('
188: q BINPUT 18
190: h BINGET 8
192: U SHORT_BINSTRING 'baz'
197: q BINPUT 19
199: u SETITEMS (MARK at 153)
200: b BUILD
201: e APPENDS (MARK at 5)
202: . STOP
Trông phức tạp! Nhưng thực sự, nó không quá tệ. pickle
về cơ bản là một máy xếp chồng, mỗi mã định danh ALL_CAPS mà bạn nhìn thấy là một mã vạch , thao tác nội bộ "ngăn xếp" theo cách nào đó để giải mã. Nếu chúng tôi đang cố gắng phân tích một số cấu trúc phức tạp, điều này sẽ quan trọng hơn, nhưng may mắn thay, chúng tôi chỉ đang tạo một danh sách đơn giản về các bản chất-tuple. Tất cả "mã" này đang làm là xây dựng một loạt các đối tượng trên ngăn xếp, và sau đó đẩy toàn bộ ngăn xếp vào một danh sách.
Một điều chúng tôi cần quan tâm là các mã 'BINPUT'/'BINGET' bạn thấy nằm rải rác xung quanh. Về cơ bản, đây là để 'ghi nhớ', để giảm bớt dấu chân dữ liệu, pickle
lưu các chuỗi với BINPUT <id>
và sau đó nếu chúng xuất hiện lại, thay vì bán lại chúng, chỉ cần đặt BINGET <id>
để truy xuất chúng từ bộ nhớ cache.
Ngoài ra, một biến chứng khác! Có nhiều hơn chỉ là SHORT_BINSTRING
- có bình thường BINSTRING
cho chuỗi> 256 byte và cũng có một số biến thể unicode thú vị. Tôi sẽ chỉ giả định rằng bạn đang sử dụng Python 2 với tất cả các chuỗi ASCII. Một lần nữa, hãy bình luận nếu đây không phải là một giả định chính xác.
OK, vì vậy, chúng tôi cần truyền trực tuyến tệp cho đến khi chúng tôi đạt đến '\ 81' byte (NEWOBJ
). Sau đó, chúng ta cần phải quét trước cho đến khi chúng ta nhấn ký tự '(' (MARK
). Sau đó, cho đến khi chúng ta nhấn 'u' (SETITEMS
), chúng ta đọc các cặp chuỗi khóa/giá trị - sẽ có tổng cộng 3 cặp, một cho Vì vậy, hãy làm điều này.Đây là kịch bản của tôi để đọc dữ liệu dưa trong thời trang trực tuyến. Nó hoàn hảo, vì tôi chỉ hack nó với nhau cho câu trả lời này, và bạn sẽ cần phải sửa đổi nó rất nhiều, nhưng đó là một khởi đầu tốt
pickledata = '\x80\x02]q\x00(c__main__\nDocument\nq\x01)\x81q\x02}q\x03(U\x04dateq\x04U\x051/1/1q\x05U\x04textq\x06U\x0bfoo is goodq\x07U\x05titleq\x08U\x03fooq\tubh\x01)\x81q\n}q\x0b(h\x04U\x052/2/2q\x0ch\x06T\x14\x05\x00\x00bar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterq\rh\x08U\x03barq\x0eubh\x01)\x81q\x0f}q\x10(h\x04U\x053/3/3q\x11h\x06U\x13no one likes baz :(q\x12h\x08U\x03bazq\x13ube.'
# simulate a file here
import StringIO
picklefile = StringIO.StringIO(pickledata)
import pickle # just for opcode names
import struct # binary unpacking
def try_memo(f, v, cache):
opcode = f.read(1)
if opcode == pickle.BINPUT:
cache[f.read(1)] = v
elif opcode == pickle.LONG_BINPUT:
print 'skipping LONG_BINPUT to save memory, LONG_BINGET will probably not be used'
f.read(4)
else:
f.seek(f.tell() - 1) # rewind
def try_read_string(f, opcode, cache):
if opcode in [ pickle.SHORT_BINSTRING, pickle.BINSTRING ]:
length_type = 'b' if opcode == pickle.SHORT_BINSTRING else 'i'
str_length = struct.unpack(length_type, f.read(struct.calcsize(length_type)))[0]
value = f.read(str_length)
try_memo(f, value, memo_cache)
return value
elif opcode == pickle.BINGET:
return memo_cache[f.read(1)]
elif opcide == pickle.LONG_BINGET:
raise Exception('Unexpected LONG_BINGET? Key ' + f.read(4))
else:
raise Exception('Invalid opcode ' + opcode + ' at pos ' + str(f.tell()))
memo_cache = {}
while True:
c = picklefile.read(1)
if c == pickle.NEWOBJ:
while picklefile.read(1) != pickle.MARK:
pass # scan forward to field instantiation
fields = {}
while True:
opcode = picklefile.read(1)
if opcode == pickle.SETITEMS:
break
key = try_read_string(picklefile, opcode, memo_cache)
value = try_read_string(picklefile, picklefile.read(1), memo_cache)
fields[key] = value
print 'Document', fields
# insert to sqllite
elif c == pickle.STOP:
break
này đọc một cách chính xác dữ liệu thử nghiệm của tôi trong định dạng dưa 2 (sửa đổi để có một chuỗi dài):.
$ python picklereader.py
Document {'date': '1/1/1', 'text': 'foo is good', 'title': 'foo'}
Document {'date': '2/2/2', 'text': 'bar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is better', 'title': 'bar'}
Document {'date': '3/3/3', 'text': 'no one likes baz :(', 'title': 'baz'}
Chúc bạn may mắn!
Máy chạy chương trình có RAM bao nhiêu RAM? – IanAuld
Sử dụng sqlite, để chọn một tệp 2.6 Gb là khá gần với sự điên rồ. Sqlite là khá dễ dàng để có được xung quanh;) – brunsgaard
Chia sẻ dữ liệu và tôi sẽ giải thích nó cho bạn hoặc thuê một máy AWS lớn cho công việc. Tôi khá chắc chắn @IanAuld là đúng .. bạn thiếu bộ nhớ. – brunsgaard