0

みなさん、こんにちは。

私は、さまざまなユーザーがチェックアウトしているツールを追跡する Raspberry Pi システムを持っています。ユーザーのチェックイン時とチェックアウト時にシステムのスキャンが実行されるように設定しました。2 つのスキャンを比較することで、ツールが持ち出されたか、または返却されたかを判断できます。ただし、現在チェックアウトされているツールを追跡する 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 ファイルを作成するにはどうすればよいでしょうか。3 つの方法:

  1. 読み取りモードで開き、ファイル全体を読み取り、閉じ、書き込みモードで開き、すべてを書き出して閉じます。
  2. に名前を変更しLog.csv.bak、それを読み取りモードで開きLog.csv、書き込みモードで開き、一方から他方にコピーします。
  3. 読み取りLog.csvモードで開き、一時ファイルを書き込みモードで開き、あるファイルから別のファイルにコピーしてから、一時ファイルの名前をアトミックに に変更しますLog.csv

通常は 3 番目の方法が最適ですが、残念ながら、クロスプラットフォームの方法で、または Windows だけでさえ、正しく行うのは非常に困難です。(ただし、Unix だけに関心がある場合は非常に簡単です。) では、2 番目の例を示します。

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 に答える