TL; DR:你能不能可靠迭代通過一個csv對象本身,或使用(如果/不在)對它呢?CSV閱讀器重複問題
所以我有一個奇怪的問題。這似乎是間歇性的,但那是因爲我不知道發生了什麼。我確定有一個真正的原因。
我有以下幾點:
import os
import csv
csv_old = 'vendor_old.csv'
csv_new = 'vendor.csv'
csv_sftp = 'vendor_sftp.csv'
def check_vendor_length():
with open(csv_old, 'r') as t_old:
vendor_old = csv.reader(t_old, delimiter = ',')
all_vendor_old = next(vendor_old)
len_vendor_old = len(all_vendor_old)
return len_vendor_old
def check_vendor_old():
with open(csv_old, 'r') as t_old, open(csv_new, 'r') as t_new, open(csv_sftp, 'w', newline = '') as t_sftp:
vendor_old = csv.reader(t_old, delimiter = ',')
vendor_new = csv.reader(t_new, delimiter = ',')
vendor_sftp = csv.writer(t_sftp, delimiter = ',')
all_vendor_old = []
row_vendor_old = next(vendor_old)
row_vendor_old.insert(csv_len, 'action')
all_vendor_old.append(row_vendor_old)
for row_vendor_old in vendor_old:
if row_vendor_old not in vendor_new:
all_vendor_old.append(row_vendor_old + ['remove'])
vendor_sftp.writerows(all_vendor_old)
def check_new():
with open(csv_old, 'r') as t_old, open(csv_new, 'r') as t_new, open(csv_sftp, 'a', newline = '') as t_sftp:
vendor_old = csv.reader(t_old, delimiter = ',')
vendor_new = csv.reader(t_new, delimiter = ',')
vendor_sftp = csv.writer(t_sftp, delimiter = ',')
all_vendor_new = []
row_vendor_new = next(vendor_new)
row_vendor_new.insert(csv_len, 'action')
for row_vendor_new in vendor_new:
all_vendor_new.append(row_vendor_new + ['add'])
vendor_sftp.writerows(all_vendor_new)
所以,第一個功能對新老CSV比較。如果舊版中的行不在新版中,則應將其標記爲刪除。他們被寫入一個(新的)CSV,將SFTP'd給供應商。
第二個函數只取得新CSV中的所有數據並將其附加到SFTP CSV中。
發生的事情是,昨晚生成的SFTP CSV具有所有內容的重複,唯一的區別是首先是「刪除」條目,然後是所有這些條目之後的相同行,但是與'添加'而不是'刪除'。
但這並不總是發生。在測試中,它按預期工作。沒有dups。但由於某種原因,昨晚的SFTP再一次擁有了所有的訣竅。正在處理的CSV只有大約10列,大約5100行。
奇怪的是,當我稍微削減一下,以至於我只用了大約2-300行時,我遇到了同樣的問題。
還有額外的代碼沒有顯示,但基本上,在SFTP CSV創建後,舊的CSV已被刪除,並且新的CSV被重命名爲舊的CSV名稱。然後,第二天,當新CSV被轉儲到目錄中時,腳本可以再次運行。沖洗並重復。
我們能確定的是,也許通過CSV對象上迭代最接近(vendor_new = csv.reader(t_new,分隔符= ''))在某種程度上borking過程。所以我做了什麼修改的check_vendor_old功能,使新的CSV被讀取到一個列表,然後再在for循環檢查對新CSV列表舊CSV行:
def check_vendor_old():
with open(csv_old, 'r') as t_old, open(csv_new, 'r') as t_new, open(csv_sftp, 'w', newline = '') as t_sftp:
vendor_old = csv.reader(t_old, delimiter = ',')
vendor_new = csv.reader(t_new, delimiter = ',')
vendor_sftp = csv.writer(t_sftp, delimiter = ',')
all_vendor_old = []
row_vendor_old = next(vendor_old)
row_vendor_old.insert(csv_len, 'action')
all_vendor_old.append(row_vendor_old)
################ NEW STUFF HERE ################
# Create list comprised of new vendor.csv rows
list_vendor_new = []
for row in vendor_new:
list_vendor_new.append(row)
# print(list_vendor_new)
################ NEW STUFF HERE ################
for row_vendor_old in vendor_old:
if row_vendor_old not in list_vendor_new:
all_vendor_old.append(row_vendor_old + ['remove'])
vendor_sftp.writerows(all_vendor_old)
所以,這一切現在似乎按預期工作......但我想我們會看到。
所以我的問題是,是否有什麼,我錯過了當閱讀csv閱讀器文檔?你能不能可靠遍歷csv對象本身,或者使用[if/not in]來對付它?它似乎在測試過程中起作用,但顯然昨晚沒有按計劃進行。
UPDATE
我發現vendor_new.seek(0)
不工作(因爲vendor_new
類是_csv.reader
,它沒有尋求方法),但t_new
(我打開CSV AS)是_io.TextIOWrapper
,裏面確實有尋找方法。
所以我想,如果我是這樣做:
def check_vendor_old():
...
for row_vendor_old in vendor_old:
if row_vendor_old not in vendor_new:
all_vendor_old.append(row_vendor_old + ['remove'])
t_new.seek(0)
這可能是更接近我想要的東西。 (如果我真的想與csv.reader對象,而不是一個列表的工作。)
謝謝你。儘管你的回答很有幫助,你能幫我澄清一下嗎?假設'vendor_new'對象由5行組成,當我做'如果row_vendor_old不在vendor_new'中時,實際發生了什麼?它是否通過'vendor_new'前進一次,然後不重置在vendor_old'循環中的下一個'for row_vendor_old?可以/應該使用'vendor_new.seek(0)'來重置'vendor_new'嗎? – thisAaronMdev
它是一個'iterator',它不是'file',它不是'list',它不是任何類型的容器。它只是一個'迭代器',**它所能做的就是向前邁進**。它不能「重置」。如果您需要繼續檢查其中的內容,請將其轉換爲適當的容器(就像在您工作的示例中一樣)。 – donkopotamus