2013-02-25 542 views
0

我試圖從csv獲取值並將它們放入數據庫中,我正在設法做到這一點,而沒有很大的麻煩。Python讀取CSV並將值存入MySQL數據庫

但我知道需要回寫到csv,所以下一次運行腳本時,它只會從csv文件中的標記下方將值輸入到數據庫中。

注意系統上的CSV文件會自動刷新每24小時,因此請記住csv中可能沒有標記。所以如果沒有標記被發現,基本上把所有的值都放在數據庫中。

我打算每30分鐘運行一次這個腳本,因此csv文件中可能會有48個標記,甚至可以刪除標記並每次將它移下文件?

我一直在刪除該文件,然後重新在腳本中創建一個文件,以便每個腳本都運行新文件,但這會打破系統的某種程度,因此這不是一個好選擇。

希望你們能幫助..

謝謝

Python代碼:

import csv 
import MySQLdb 

mydb = MySQLdb.connect(host='localhost', 
user='root', 
passwd='******', 
db='kestrel_keep') 

cursor = mydb.cursor() 

csv_data = csv.reader(file('data_csv.log')) 

for row in csv_data: 

    cursor.execute('INSERT INTO `heating` VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s,)', 
    row) 
#close the connection to the database. 
mydb.commit() 
cursor.close() 
import os 


print "Done" 

我的CSV文件格式:

2013-02-21,21:42:00,-1.0,45.8,27.6,17.3,14.1,22.3,21.1,1,1,2,2 
2013-02-21,21:48:00,-1.0,45.8,27.5,17.3,13.9,22.3,20.9,1,1,2,2 

回答

1

我認爲這不是一個更好的選擇「標記」CSV文件是爲了保存文件,你是否存儲了你處理的最後一行的編號。

因此,如果文件不存在(一個是存儲最後處理的行的編號),則會處理整個CSV文件。如果此文件存在,則僅處理此行後的記錄。

終極密碼在工作系統:

#!/usr/bin/python 
import csv 
import MySQLdb 
import os 

mydb = MySQLdb.connect(host='localhost', 
user='root', 
passwd='*******', 
db='kestrel_keep') 

cursor = mydb.cursor() 

csv_data = csv.reader(file('data_csv.log')) 

start_row = 0 

def getSize(fileobject): 
fileobject.seek(0,2) # move the cursor to the end of the file 
size = fileobject.tell() 
return size 

file = open('data_csv.log', 'rb') 
curr_file_size = getSize(file) 

# Get the last file Size 
if os.path.exists("file_size"): 
with open("file_size") as f: 
    saved_file_size = int(f.read()) 


# Get the last processed line 
if os.path.exists("lastline"): 
with open("lastline") as f: 
    start_row = int(f.read()) 


if curr_file_size < saved_file_size: start_row = 0 

cur_row = 0 
for row in csv_data: 
if cur_row >= start_row: 
    cursor.execute('INSERT INTO `heating` VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s ,%s)', row) 

    # Other processing if necessary 

cur_row += 1 

mydb.commit() 
cursor.close() 


# Store the last processed line 
with open("lastline", 'w') as f: 
start_line = f.write(str(cur_row + 1)) # you want to start at the **next** line 
             # next time 
# Store Current File Size To Find File Flush  
with open("file_size", 'w') as f: 
start_line = f.write(str(curr_file_size)) 

# not necessary but good for debug 
print (str(cur_row)) 



print "Done" 

編輯:終極密碼由ZeroG提供Submited現在工作在系統上!謝謝你也是太Xion345幫助

+0

我喜歡這個答案,但我不能得到行我們正在放入0以上的最後一行文件甚至'(str(cur_row))'reviles 0 ...也記住當文件在00:01刷新: 00行號不會相對於新的csv文件,所以我想我們需要檢查某處的時間 – ZeroG 2013-02-25 16:48:26

+0

是的,你說得對,代碼錯了,你需要在結尾處移動'cur_row + = 1'語句for循環。至於00:01的刷新,你需要檢查當前時間和最後一行文件的寫入日期。 – Xion345 2013-02-25 17:14:34

+0

@ZeroG:檢測文件是否已被刷新的更好的辦法是將CSV文件的大小存儲在最後一行文件中(除了最後一個處理過的行)。如果文件大小在腳本的兩次後續執行之間減少,則知道CSV文件已被刷新。 – Xion345 2013-02-25 17:21:50

1

每個csv行似乎都包含一個時間戳。如果這些數據總是增加,則可以查詢數據庫以獲取已記錄的最大時間戳,並在讀取csv之前跳過所有行。

2

它看起來像你的MySQL表中的第一個字段是唯一的時間戳。可以設置MySQL表,使該字段必須是唯一的,並忽略違反該唯一性屬性的INSERT。在mysql>提示符下輸入命令:

ALTER IGNORE TABLE heating ADD UNIQUE heatingidx (thedate, thetime)  

(更改thedatethetime持有的日期和時間列的名稱。)


一旦你做出這個變化到你的數據庫,你只需要改變一行在你的程序,以使MySQL忽略重複插入:

cursor.execute('INSERT IGNORE INTO `heating` VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s,)', row) 

是的,這是一個小浪費了INSERT IGNORE ...已經處理過的線路上,但考慮到你的數據頻率(每6分鐘?),它在性能方面不會有太大影響。

這樣做的好處是現在不可能無意中將重複項插入到表中。它還使程序的邏輯簡單易讀。

它還避免了兩個程序同時寫入同一個CSV文件。即使您的程序通常成功沒有錯誤,每隔一段時間 - 也許一次在藍色月亮中 - 您的程序和其他程序可能會嘗試同時寫入文件,這可能會導致錯誤或損壞數據。


您也可以使你的程序更快一點用cursor.executemany代替cursor.execute

rows = list(csv_data) 
cursor.executemany('''INSERT IGNORE INTO `heating` VALUES 
    (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s,)''', rows) 

相當於

for row in csv_data:  
    cursor.execute('INSERT INTO `heating` VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s,)', 
    row) 

除了它所有的數據包到一個命令。

+0

我喜歡那個,但日期和時間是兩個單獨的字段??? – ZeroG 2013-02-25 16:49:00

+0

@ZeroG:沒問題。只需列出定義唯一行所需的所有字段。我已經編輯了上面的帖子來展示我的意思。 – unutbu 2013-02-25 19:03:12

+0

這是否考慮到日期和時間需要不同,即在2天內有2個14:00,即使日期會不同? – ZeroG 2013-02-25 20:35:11