是否有一种明智的方法来更新CSV数据,在同一文件中,一次一行?
我有一个CSV的记录要检查并可能修复,这是我用临时脚本解决的一次性任务。该脚本将需要迭代才能使其正确工作。它将对每个记录进行分类,决定一个操作,尝试该操作并记录结果。我想将这些阶段附加到CSV:
id,status,action,result
123
234
345
456
id,status,action,result
123,OK,None
234,INVALID,Fix,OK
345,INVALID,Fix
456
哦,不,我的脚本崩溃,而试图修复345由于一个bug!因此,我将修复该错误并再次运行脚本,它将跳过status:OK
或result:OK
:
id,status,action,result
123,OK,None
234,INVALID,Fix,OK
345,INVALID,Fix,OK
456,OK,None
这可能吗?
一种方法是将CSV加载到内存中,然后覆盖原始文件:
fieldnames = "id status action result".split()
data = []
def process_and_update(record):
if record["status"] != "OK":
...
with open("file.csv", "r", newline="") as input_file:
reader = csv.DictReader(input_file, fieldnames=fieldnames)
next(reader) # skip header row
for r in reader:
data.append(r)
with open("file.csv", "w", newline="") as output_file:
writer = csv.DictWriter(output_file, fieldnames=fieldnames)
writer.writeheader()
for record in data:
process_and_update(record)
writer.writerow(record)
这不起作用,因为如果process_and_update(record)
抛出意外错误,那么剩余的数据将丢失。
我目前使用的方法是写入一个单独的文件:
with open("file1.csv", "r", newline="") as input_file,
open("file2.csv", "w", newline="") as output_file:
reader = csv.DictReader(input_file, fieldnames=fieldnames)
next(reader)
writer = csv.DictWriter(output_file, fieldnames=fieldnames)
writer.writeheader()
for record in reader:
record.update(process_and_update(record))
writer.writerow(record)
但是这需要每次为脚本提供正确的文件名。如果我继续使用原始文件作为输入,它将一遍又一遍地进行状态检查,这是缓慢的。
或者我应该将数据放入sqlite文件中?
找到了另一个部分答案,但如果存在未处理的错误,则会损坏文件:
with open(filename, "r", newline="") as input_file,
open(filename, "r+", newline="") as output_file:
reader = csv.DictReader(input_file)
writer = csv.DictWriter(output_file, fieldnames=reader.fieldnames)
writer.writeheader()
for record in reader:
print(f"{record['id']}... ", end="")
if record["id"] == "345":
print("Fail")
raise Exception("simulated crash")
else:
print("OK")
record["result"] = "OK"
writer.writerow(record)
在with output_file
上下文结束时,将DictWriter
写入文件。如果由于未处理的异常而结束,则部分覆盖原始文件:
id,status,action,result
123,
234,
345,
456,
567,
678,
789,
890,
id,status,action,result
123,,,OK
234,,,OK
6, <--- "345,n456," overwritten
567,
678,
789,
890,
所以,如果你确信你永远不会崩溃,这个解决方案是有效的。否则,最好使用单独的输入文件和输出文件。