使用Python 3更新CSV文件(添加/删除行)

时间:2013-07-15 22:26:19

标签: python csv rows

G'大家,

我有一个Raspberry Pi系统,可以跟踪各种用户检出的工具。我进行了设置,以便在用户办理登机手续以及结帐时执行系统扫描。通过比较两次扫描,我可以确定是否已经采取/返回工具。但是,我还有一个Log.csv文件,用于跟踪当前检出的工具。我可以在签出工具时添加到此日志中(这里没有问题),但是在返回工具时我无法删除该行。

我已经搜索过SO以寻求解决方案,但没有找到具体的解决方案。根据我的理解,您无法从CSV文件中删除单行?我将不得不重写该文件,并忽略该特定行?

这是我到目前为止所做的,包括在Log.csv文件中添加和删除行:

with open('Log.csv', 'a+') as f:
    reader = csv.reader(f)
    if tools_taken not in reader:
        csv.writer(open('Log.csv', 'a+')).writerow([tools_taken])

with open('Log.csv', 'a+') as f:
    reader = csv.reader(f)
    if tools_returned in reader:
        ???

请记住,上面的代码已经过简化,以保持简洁。我认为,如果工具在阅读器中回归,那么线太模糊了。我可能会改为:

for row in reader:
    for field in row:
        if field == tools_taken:
            ???

我是否在正确的轨道上?这里的任何输入都将非常感谢!

2 个答案:

答案 0 :(得分:1)

  

根据我的理解,您无法从CSV文件中删除单行?我将不得不重写该文件,并忽略该特定行?

完全。事实上,对于一般的文件来说也是如此。为了从文件中间删除东西,你必须向上移动文件的其余部分,然后截断留下的残骸。您通常不想这样做,因此csv模块无法帮助您完成此操作。


那么,您如何创建新的CSV文件?三种方式:

  1. 以读取模式打开,读取整个文件,关闭,打开写入模式,写出整个文件,关闭。
  2. 重命名为Log.csv.bak,在读取模式下打开,在写入模式下打开Log.csv,然后从一个复制到另一个。
  3. 在读取模式下打开Log.csv,以写入模式打开临时文件,从一个复制到另一个,然后将临时文件原子重命名为Log.csv

  4. 第三个通常是最好的 - 但不幸的是,很难以跨平台的方式,甚至只是为了Windows。 (但是,如果你只关心Unix,这很容易。)所以,我将展示第二个:

    os.rename('Log.csv', 'Log.csv.bak')
    with open('Log.csv.bak') as infile, open('Log.csv', 'w') as outfile:
        reader = csv.reader(infile)
        writer = csv.writer(outfile)
        for row in reader:
            if not supposed_to_be_removed(row):
                writer.writerow(row)
    

    就是这样。


    这类似于编写复制算法代替简单列表的变异算法的方式:

    newlist = [row for row in oldlist if not supposed_to_be_removed(row)]
    

    当然,您可以根据迭代器而不是列表来编写它:

    newlist = (row for row in oldlist if not supposed_to_be_removed(row))
    

    事实上,你可以在这里使用完全相同的迭代器:

    os.rename('Log.csv', 'Log.csv.bak')
    with open('Log.csv.bak') as infile, open('Log.csv', 'w') as outfile:
        reader = csv.reader(infile)
        writer = csv.writer(outfile)
        newrows = (row for row in reader if not_supposed_to_be_removed(row))
        writer.writerows(newrows)
    

    如果你愿意,你甚至可以把它变成一个单行:

        writer.writerows(row for row in reader if not supposed_to_be_removed(row))
    

    最后,可能值得考虑一下csv文件是否真的是正确答案。如果你正在做一大堆操作,不断重读和重复写文件将会很痛苦 - 而且速度很慢。也许你可以将它保存在内存中,只需读写,启动和关闭,但是你必须确保不丢失错误数据。请参阅我的其他答案以获得另一种选择。

答案 1 :(得分:1)

我不认为csv是正确的结构。您希望能够查找给定工具,找出其tools_taken是否为True,或更改其tools_taken,还是从文件中删除工具,或者将工具添加到文件中, ?

这就是数据库的用途,例如shelve

import contextlib
import shelve

tools = shelve.open('Log.db', 'c', writeback=True)
with contextlib.closing(tools):
    # Add a tool
    tools['hammer'] = {'name': 'Hammer', 'owner': 'Joe', 'tools_taken': False}
    # Check if a tool is taken
    if tools['screwdriver']['tools_taken']:
        print('The screwdriver is taken!')
    # Change a tool's taken status:
    tools['screwdriver']['tools_taken'] = True
    # Remove a tool
    del tools['jackhammer']

换句话说,你可以就像一个dict(在这种情况下,充满dict s),但它在运行中自动持久。