首页 > 解决方案 > 如何使用 Python 有效地读取带有自定义换行符的大文件?

问题描述

我们有一个巨大的.csv文件,但它似乎并不是真正的 csv。

行尾是\tl\n.
此换行符之间的文本有时具有“真正的”换行符。我们不想在这些问题上分裂。

我们目前使用awk.

awk_code = r'BEGIN{ RS="""(\tl\n)"""; FS="\t"} { print "\42"$1"\42,\42"$2"\42,\42\42\42"$3"\42\42\42,\n";}'
bash_command_awk = f"awk '{awk_code}' {input_file_path} > {output_path}"
awk_command_output = subprocess.check_output(bash_command_awk,stderr=subprocess.STDOUT, shell=True)

我正在尝试找到一种直接在 Python 中执行此操作的有效方法,并尝试将自定义换行符传递给.open()命令。

def process_without_putting_file_in_RAM(file_to_process):
    with file_to_process.open(encoding="utf-8", newline="\tl\n") as csv_file:
        for line in csv.reader(csv_file):

但是,我很快了解到换行 arg 只接受一个默认字符。

如何有效地处理这个包含奇怪行尾的文件?

标签: python

解决方案


这是一个可以正确处理块之间的多字符换行符的函数

def line_splitter(file, newline, chunk_size=4096):
    tail = ''
    while True:
        chunk = file.read(chunk_size)
        if not chunk:
            if tail:
                yield tail
            break
        lines = (tail + chunk).split(newline)
        tail = lines.pop(0)
        if lines:
            yield tail
            tail = lines.pop()
            yield from lines

另一个版本,虽然它不会复制整个块并没有证明更快。对于大块,它会稍微快一些。不要使用小于换行大小的 chunk_size :)

def line_splitter(file, newline, chunk_size=4096):
    tail = ''
    while True:
        chunk = file.read(chunk_size)
        if not chunk:
            if tail:
                yield tail
            break
        lines = chunk.split(newline)
        tail = (tail + lines[0]).split(newline)
        if len(tail) > 1:
            lines[0] = tail[1]
        else:
            del lines[0]
        tail = tail[0]
        if lines:
            yield tail
            tail = lines.pop()
            yield from lines

调用者应该是这样的:

with longabstract_file.open() as f:
    for line in line_splitter(f, "\tl\n"):
        if line: # ignore blank lines
            print(line)

推荐阅读