在Python中,逐行阅读大型文本文件非常简单:
for line in open('somefile', 'r'): ...
但是如何读取二进制文件并通过某个给定标记“拆分”(通过生成器)其内容,而不是换行符'\ n'?
我想要这样的东西:
content = open('somefile', 'r').read()
result = content.split('some_marker')
但是,当然,内存效率高(文件大约70GB)。当然,我们无法通过每个字节读取文件(由于硬盘性质,它会太慢)。
“块”长度(这些标记之间的数据)可能不同,理论上从1字节到兆字节。
所以,举一个总结的例子,数据看起来像这样(这里的数字是指字节,数据是二进制格式):
12345223-MARKER-3492-MARKER-34834983428623762374632784-MARKER-888-MARKER-...
有没有简单的方法可以做到这一点(没有实现读取块,拆分块,记住尾部等)?
答案 0 :(得分:5)
Python中没有任何神奇的功能可以为你做到,但写起来并不难。例如:
def split_file(fp, marker):
BLOCKSIZE = 4096
result = []
current = ''
for block in iter(lambda: fp.read(BLOCKSIZE), ''):
current += block
while 1:
markerpos = current.find(marker)
if markerpos == -1:
break
result.append(current[:markerpos])
current = current[markerpos + len(marker):]
result.append(current)
return result
通过将此函数转换为生成器,即将result.append(...)
转换为yield ...
,可以进一步减少此函数的内存使用量。这留给读者作为练习。
答案 1 :(得分:2)
一般的想法是使用mmap
然后re.finditer
覆盖它:
import mmap
import re
with open('somefile', 'rb') as fin:
mf = mmap.mmap(fin.fileno(), 0, access=mmap.ACCESS_READ)
markers = re.finditer('(.*?)MARKER', mf)
for marker in markers:
print marker.group(1)
我还没有测试过,但您可能也需要(.*?)(MARKER|$)
或类似的内容。
然后,由操作系统提供访问该文件的必要条件。
答案 2 :(得分:1)
我认为没有任何内置函数,但你可以使用迭代器很好地“读入块”以防止内存效率低下,类似于@ user4815162342的建议:
def split_by_marker(f, marker = "-MARKER-", block_size = 4096):
current = ''
while True:
block = f.read(block_size)
if not block: # end-of-file
yield current
return
current += block
while True:
markerpos = current.find(marker)
if markerpos < 0:
break
yield current[:markerpos]
current = current[markerpos + len(marker):]
这样你就不会立刻将所有结果保存在内存中,你仍然可以像下面那样迭代它:
for line in split_by_marker(open(filename, 'rb')): ...
确保每条“线”都不会占用太多内存......
答案 3 :(得分:0)
Readline本身读取块,分割块,记住尾巴等等。所以,不。