0

大家好,

我有一个 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:
        ???

请记住,上面的代码已被简化以保持简洁。我在想“if tools_returned in reader”这一行太含糊了。我可能会将其更改为:

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

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

4

2 回答 2

1

据我了解,您不能从 CSV 文件中删除一行?我将不得不重写文件,并省略该特定行?

确切地。事实上,这对于一般文件来说是正确的。为了从文件中间删除东西,您必须向上移动文件的整个其余部分,然后截断留下的部分。您通常不想这样做,因此该csv模块不会帮助您这样做。


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

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

第三个通常是最好的——但不幸的是,很难以跨平台的方式正确使用它,甚至仅适用于 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文件是否真的是正确的答案。如果您正在执行一大堆操作,那么一遍又一遍地不断地重新读取和重写文件将是一件痛苦的事情——而且速度很慢。也许你可以把它保存在内存中,然后读写、启动和关闭,但是你必须确保你不会因为错误而丢失数据。请参阅我的其他答案以获取另一种选择。

于 2013-07-15T22:35:36.300 回答
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']

换句话说,你可以像 a 一样dict(在这种情况下,充满dicts),但它会在运行中自动持久化。

于 2013-07-15T22:48:57.710 回答