首页 > 解决方案 > 如何用单行拆分大文件?

问题描述

我有包含以下详细信息的输入文件:

文件大小:大约 3GB 到 5GB
行数:1(总是)
分隔符:_@%@_
文件类型:二进制
文件扩展名:txt
每个分隔符之间的数据大小:最大 5MB 每个分隔符之间
的数据长度:不可预测
可能有任何字符 [ _, @, %] 介于两者之间:是

示例

_@%@_4fdadfdcdfrffe3q_@%@_dfdsd8fs7dff9_@%@_jfdksadfdsfsdfjsalj_@%@_fsadklfjsdfewer0_@%@_dfsdfjsdlfdffdufdfudyfdf_@%@_

实际上,该文件包含用 . 分隔的多行_@%@_。问题是没有换行符,因此我无法用_@%@_

我尝试分割线。但是得到MemoryError(在线inputF.read())。
我想,如果我使用for line in open(inputFilePath):, 会得到MemoryError它自己,因为文件中只有一行(没有尝试过)。

inputF=open(inputFilePath, "r") 
fullFile = inputF.read()
splitted = fullFile.split("_@%@_")

预期输出(阅读后,我必须将每一行转换为人类可读的格式)

shirt
form
some 
human
readable

如果我尝试将其读取为块,如何正确拆分它以获得精确的行?
(比如说,我可能会得到_@%@_4fdadfdcdf第一块和rffe3q_@%@_dfdsd8第二块,对吧?)

更新
将分隔符从 更改###_@%@_。由于我不应该提供实际数据,我想只提供一个分隔符。没想过一个字一个字地读。

标签: pythonsplitdelimiterlarge-data

解决方案


解决方案 1

使用mmap(修改其示例代码)和正则表达式:

import mmap, re

# write a simple example file
with open("hello.txt", "wb") as f:
    f.write(b"_@%@_4fdadfdcdfrffe3q_@%@_dfdsd8fs7dff9_@%@_jfdksadfdsfsdfjsalj_@%@_fsadklfjsdfewer0_@%@_dfsdfjsdlfdffdufdfudyfdf_@%@_")

with open("hello.txt", "r+b") as f:
    mm = mmap.mmap(f.fileno(), 0)
    for match in re.finditer(b'(?<=_@%@_)(.*?)(?=_@%@_)', mm):
        print(match[1])

输出(在线尝试!):

b'4fdadfdcdfrffe3q'
b'dfdsd8fs7dff9'
b'jfdksadfdsfsdfjsalj'
b'fsadklfjsdfewer0'
b'dfsdfjsdlfdffdufdfudyfdf'

没有将分隔符硬编码到模式中的版本(在线试用!):

delimiter = '_@%@_'
with open("hello.txt", "r+b") as f:
    mm = mmap.mmap(f.fileno(), 0)
    ed = re.escape(delimiter)
    for match in re.finditer(f'(?<={ed})(.*?)(?={ed})'.encode(), mm):
        print(match[1])

解决方案 2

mmap单独使用:

import mmap

# write a simple example file
with open("hello.txt", "wb") as f:
    f.write(b"_@%@_4fdadfdcdfrffe3q_@%@_dfdsd8fs7dff9_@%@_jfdksadfdsfsdfjsalj_@%@_fsadklfjsdfewer0_@%@_dfsdfjsdlfdffdufdfudyfdf_@%@_")

delimiter = b'_@%@_'
with open("hello.txt", "r+b") as f:
    mm = mmap.mmap(f.fileno(), 0)
    start = mm.find(delimiter) + len(delimiter)
    while (stop := mm.find(delimiter, start)) != -1:
        print(mm[start:stop])
        start = stop + len(delimiter)

输出:

b'4fdadfdcdfrffe3q'
b'dfdsd8fs7dff9'
b'jfdksadfdsfsdfjsalj'
b'fsadklfjsdfewer0'
b'dfsdfjsdlfdffdufdfudyfdf'

笔记

在所有情况下,如果您想要str代替bytes,请应用.decode()到结果。


推荐阅读