我正在编写一个脚本,该脚本读取文件的文件夹(每个文件的大小从20 MB到100 MB不等),修改每行中的一些数据,然后写回文件的副本。

with open(inputPath, 'r+') as myRead:
     my_list = myRead.readlines()
     new_my_list = clean_data(my_list)
with open(outPath, 'w+') as myWrite:
     tempT = time.time()
     myWrite.writelines('\n'.join(new_my_list) + '\n')
     print(time.time() - tempT)
print(inputPath, 'Cleaning Complete.')

在使用90 MB文件(〜900,000行)运行此代码时,它打印140秒作为写入文件所需的时间。在这里,我使用了writelines()。因此,我寻找了提高文件写入速度的不同方法,并且在我阅读的大多数文章中,它都说write()writelines()应该没有任何区别,因为我只写了一个串联字符串。我还检查了以下语句所需的时间:
new_string = '\n'.join(new_my_list) + '\n'

而且只花了0.4秒,因此花费的时间并不是因为创建列表。
只是为了尝试write()我尝试了以下代码:
with open(inputPath, 'r+') as myRead:
     my_list = myRead.readlines()
     new_my_list = clean_data(my_list)
with open(outPath, 'w+') as myWrite:
     tempT = time.time()
     myWrite.write('\n'.join(new_my_list) + '\n')
     print(time.time() - tempT)
print(inputPath, 'Cleaning Complete.')

它打印了2.5秒。为什么即使是相同的数据,write()writelines()的文件写入时间也有如此大的差异?这是正常现象还是我的代码有问题?两种情况下的输出文件似乎都是相同的,所以我知道数据没有丢失。

最佳答案

file.writelines()期望字符串可迭代。然后,它继续循环并为iterable中的每个字符串调用file.write()。在Python中,该方法执行以下操作:

def writelines(self, lines)
    for line in lines:
        self.write(line)

您传入一个大字符串,并且字符串也是字符串的可迭代项。迭代时,您会得到单个字符,长度为1的字符串。因此,实际上,您是在对len(data)进行file.write()的单独调用。这很慢,因为您一次要建立一个字符的写缓冲区。

不要将单个字符串传递给file.writelines()。传入列表或元组或其他可迭代对象。

您可以发送单独的行,并在生成器表达式中添加换行符,例如:
 myWrite.writelines(line + '\n' for line in new_my_list)

现在,如果您可以将clean_data()生成为生成器,并产生干净的行,则可以将输入文件中的数据通过数据清理生成器进行流传输,然后输出到输出文件中,而无需使用比读写缓冲区所需的更多内存和但是需要很多状态来清理您的线路:
with open(inputPath, 'r+') as myRead, open(outPath, 'w+') as myWrite:
    myWrite.writelines(line + '\n' for line in clean_data(myRead))

另外,我会考虑更新clean_data()以发出包含换行符的行。

10-07 17:48