如何使用Python有效地读取带有自定义换行符的大文件?

时间:2018-10-12 22:09:10

标签: python

我们有一个庞大的@effect() add$ = this.actions$ .ofType<Add>(ADD) .pipe(mergeMap(a => this.sharedService.add(a.entity, a.api) .pipe(map(s => new AddResult(Ok(s.id)))) .pipe(catchError(e => of(new AddResult(Err(e))))))); 文件,但它似乎并不是真的csv。

行尾为.csv
此换行符之间的文本有时具有“真实”换行符。我们不想在这些问题上分开。

我们目前使用\tl\n进行操作。

awk

我试图找到一种直接在Python中执行此操作的有效方法,并尝试将自定义换行符传递到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) 命令中。

.open()

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

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

3 个答案:

答案 0 :(得分:1)

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

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)

答案 1 :(得分:0)

假设您的csv是用逗号或空格分隔,而不是制表符,那么您要查找的是lineterminator flag,但由于自动假定'\n'是一个换行符,因此不需要这样做。来自文档:

  

注意:阅读器经过硬编码,可以将'\r''\n'识别为   行尾,并忽略lineterminator。这种行为可能会改变   未来。

所以您可以做的是添加字符串方法.replace()来摆脱'\tl'这样的情况

def process_without_putting_file_in_RAM(file_to_process):
    with file_to_process.open(encoding="utf-8") as csv_file:
        for line in csv.reader(csv_file, delimiter=","):
            print(line[-1].replace('\tl', ''))

答案 2 :(得分:-1)

为什么不使用pandas。具体来说,pandas.read_csv使用lineterminatorchunksize参数:

import pandas as pd

batch_size = 10000
new_line_str = '\tl\n'
iterator_df = pd.read_csv(file_to_process, chunksize=batch_size, lineterminator=new_line_str)
for chunk in iterator_df:
    # process chunk here