2013-07-15 91 views
0

天兒真好大家,更新CSV文件(添加/刪除行)與Python 3

我有一個樹莓派系統跟蹤的工具,通過各種用戶被檢查出來。我已經設置好了,以便在用戶簽入時以及簽出時執行系統掃描。通過比較兩次掃描,我可以確定工具是否已被採用/返回。但是,我也有一個Log.csv文件,用於跟蹤當前檢出哪些工具。當一個工具被檢出(這裏沒有問題)時,我可以添加到這個日誌中,但是在返回工具時我無法刪除該行。

我已經搜索過這個解決方案,但沒有找到具體的東西。據我所知,你不能從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: 
      ??? 

我在正確的軌道上嗎?任何輸入在這裏將非常感謝!

回答

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),但它跨越的自動持久運行。

+0

謝謝你,這看起來比繼續沿着CSV路線簡單得多。我之前從未使用Python的數據庫,所以可能需要一些玩弄,但這絕對是實現我想要的最合適的手段。謝謝! – jars121

+1

@ jars121:類似'sqlite3'的_real_數據庫稍微複雜一點......但是一個簡單的'dbm'或'shelve'數據庫比使用'dict'稍微難一些。 (但是有一些注意事項,所以一定要閱讀文檔。) – abarnert

+0

我是Python的新手,所以我還沒有使用過字典,但我會在那一個上寫下你的話!擱置數據庫看起來非常適合這個應用程序,所以感謝您的關注! – jars121

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文件是否真的是正確的答案在這裏它可能是值得考慮的。如果你正在進行大量的操作,不斷重複讀取和重複寫入文件將是一件痛苦的事情,而且會很慢。也許你可以將它保存在內存中,只需讀寫,啓動和關閉,但必須確保不會丟失錯誤數據。看到我的另一個答案另一個選擇。

+0

謝謝你的出色,詳細的回覆。上面的選項3的確是我從我的研究中推測出來的。與以下回應一樣,我不認爲CSV在這裏是正確的選擇。我在泵的幫助下完成原型工作,而且我也有使用CSV的經驗,儘管很少。我一定會從現在開始轉向數據庫! – jars121

+1

如果你在Unix上,並且無法自己弄清楚,我可以用'tempfile.NamedTemporaryFile'來演示如何做選項3。 (儘管我敢打賭,已經回答了SO,所以請先嚐試搜索。) – abarnert

+0

我確實在Unix上運行Raspberry Pi的Raspbian Linux。長期目標是將這個系統與各種Windows應用程序同步,所以我認爲從一開始就保持跨平臺兼容性是一個好主意。 – jars121