【问题标题】:Python - Most efficient to overwrite a specific row in a CSV filePython - 最有效地覆盖 CSV 文件中的特定行
【发布时间】:2019-02-28 12:13:20
【问题描述】:

鉴于以下 csv 文件:

01;blue;brown;black
02;glass;rock;paper
03;pigeon;squirel;shark

我的目标是替换第一个位置包含“02”的(唯一)行。

我写了这段代码:

with open("csv", 'r+', newline='', encoding='utf-8') as csvfile, open('csvout', 'w', newline='', encoding='utf-8') as out:
    reader = csv.reader(csvfile, delimiter=';')
    writer = csv.writer(out, delimiter=';')
    for row in reader:
        if row[0] != '02':
            writer.writerow(row)
        else:
            writer.writerow(['02', 'A', 'B', 'C'])

但在另一个文件中重写整个 CSV 似乎并不是最有效的方法,尤其是对于大文件:

  1. 一旦找到匹配项,我们就会继续阅读直到最后。
  2. 我们必须逐行重写。
  3. 写第二个文件不是很实用,存储也不是 高效。

我写了第二段代码,似乎可以回答这两个问题:

with open("csv", 'r+', newline='', encoding='utf-8') as csvfile:
    content = csvfile.readlines()
    for index, row in enumerate(content):
        row = row.split(';')
        if row[2] == 'rock':
            tochange = index
            break
    content.pop(tochange)
    content.insert(tochange, '02;A;B;C\n')
    content = "".join(content)
    csvfile.seek(0)
    csvfile.truncate(0)     # Erase content
    csvfile.write(content)

您是否同意第二种解决方案更有效? 您有任何改进或更好的方法吗?

编辑:行中的字符数可以变化。

编辑 2 :如果我不想使用填充,我显然有义务阅读和重写所有内容。 一个可能的解决方案是类似数据库的解决方案,我会在未来考虑它。

如果我必须在这两种解决方案之间进行选择,哪一种在性能方面是最好的?

【问题讨论】:

  • CSV 文件是否按第一列排序?如果是这样,您可以 binary-search and overwrite O(logn) 中的特定行,但您必须用相同数量的字符覆盖它。
  • 顺便说一句,在您的第二个代码中,您仍在读写整个文件。
  • 我的 CSV 实际上是按第 4 列排序的,从第二行的 00000001 开始(列 desc 的第一行)。 char 的数量可以变化。
  • 好吧,您仍然可以对该行进行线性搜索,使用seek 回溯到行的开头,然后仅覆盖这一行,用例如填充它。达到旧长度的空间,除非旧行太短,否则您也必须覆盖文件中的所有以下行(直到您找到之前已填充的另一行并且您可以删除该填充)。
  • 这确实可以解决问题,但我想避免使用填充。

标签: python csv row python-3.7


【解决方案1】:

由于行中的字符可能会有所不同,我要么必须读/写整个文件,要么;正如@tobias_k 所说,使用 seek() 回到行首并:

  • 如果该行较短,则只写该行并用空格填充;
  • 如果长度相同,只写一行;
  • 如果它更长,请重写该行和以下内容。

我想避免使用填充,所以我使用 time.perf_counter() 来测量两个代码的执行时间,第二个解决方案似乎更快(几乎 2*)(CSV 为 10 000行,匹配第 6 000 行)。

另一种方法是迁移到关系数据库

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-05-20
    • 2019-05-22
    • 2021-07-19
    • 1970-01-01
    • 1970-01-01
    • 2017-09-07
    • 2018-08-27
    相关资源
    最近更新 更多