按索引高效地向文件添加多行



给定一个输入文件data.dat如下所示:

# Some comment
# more comments
#
45.78
# aaa
0.056
0.67
# aaa
345.
0.78
99.
2.34
# aaa
65.7
0.9

我需要在以" # aaa"开头的每一行上方添加不同的注释,因此它看起来像这样:

# Some comment
# more comments
#
45.78
# cmmt1
# aaa
0.056
0.67
# another cmmt
# aaa
345.
0.78
99.
2.34
# last one
# aaa
65.7
0.9

我先验地知道data.dat文件中存在的"# aaa"评论的数量,但不知道它们的位置

我有办法做到这一点(见下面的代码(,但它非常复杂,效率不高。我需要将此代码应用于数百个大文件,因此我正在寻找一种有效的方法来执行此操作。


# Read file
with open("data.dat", mode="r") as f:
    data = f.readlines()
# Indexes of "# aaa" comments
idx = []
for i, line in enumerate(data):
    if line.startswith("# aaa"):
        idx.append(i)
# Insert new comments in their proper positions
add_data = ["# cmmt1n", "# another cmmtn", "# last onen"]
for i, j in enumerate(idx):
    data.insert(j + i, add_data[i])
# Write final data to file
with open("data_final.dat", mode="w") as f:
    for item in data:
        f.write("{}".format(item))
我没有

做任何基准测试,但re.sub可能会更快 - 只需加载整个文本文件,执行re.sub并将其写出来:

data = '''# Some comment
# more comments
#
45.78
# aaa
0.056
0.67
# aaa
345.
0.78
99.
2.34
# aaa
65.7
0.9'''
import re
def fn():
    add_data = ["# cmmt1n", "# another cmmtn", "# last onen"]
    for d in add_data:
        yield d
out = re.sub(r'^# aaa', lambda r, f=fn(): next(f) + r.group(0), data, flags=re.MULTILINE)
print(out)

指纹:

# Some comment
# more comments
#
45.78
# cmmt1
# aaa
0.056
0.67
# another cmmt
# aaa
345.
0.78
99.
2.34
# last one
# aaa
65.7
0.9

使用文件输入/输出:

import re
def fn():
    add_data = ["# cmmt1n", "# another cmmtn", "# last onen"]
    for d in add_data:
        yield d
with open('data.dat', 'r') as f_in, 
    open('data.out', 'w') as f_out:
    f_out.write(re.sub(r'^# aaa', lambda r, f=fn(): next(f) + r.group(0), f_in.read(), flags=re.MULTILINE))

版本2:

import re
def fn():
    add_data = ["# cmmt1n", "# another cmmtn", "# last onen"]
    add_data = [s + '#aaa' for s in add_data]
    for d in add_data:
        yield d
with open('data.dat', 'r') as f_in, 
    open('data.out', 'w') as f_out:
    f_out.write(re.sub(r'^# aaa', lambda r, f=fn(): next(f), f_in.read(), flags=re.MULTILINE))

根据Jan-Philip Gehrcke在这里的回应,你应该减少write呼叫的数量。

为此,您可以简单地更改:

with open("data_final.dat", mode="w") as f:
    for item in data:
        f.write("{}".format(item))

自:

with open("data_final.dat", mode="w") as f:
    f.write("".join(data))
<</div> div class="one_answers">

当我需要更改文本文件中的数据时,我尝试使用一个句柄读取并立即使用第二个句柄写入。

def add_comments(input_file_name, output_file_name, list_of_comments):
    comments = iter(list_of_comments)  # or itertools.cycle(list_of_comments)
    with open(input_file_name) as fin, open(output_file_name, 'w') as fout:
        for line in fin:
            if line.startswith("# aaa"):
                fout.write(next(comments))
            fout.write(line)

对于示例代码,if 将调用为:

add_comments("data.dat", "final_data.dat", ["# cmmt1n", "# another cmmtn", "# last onen"])

最新更新