我正在尝试比较两个csv文件(fileA和fileB),并从fileB中删除fileB中找不到的任何行。我希望能够在不创建第三个文件的情况下执行此操作。我以为我可以使用csv编写器模块做到这一点,但现在我第二次猜测自己。
目前,我正在使用以下代码记录文件B中的比较数据:
removal_list = set()
with open('fileB', 'rb') as file_b:
reader1 = csv.reader(file_b)
next(reader1)
for row in reader1:
removal_list.add((row[0], row[2]))
这是我被困住的地方,不知道如何删除行:
with open('fileA', 'ab') as file_a:
with open('fileB', 'rb') as file_b:
writer = csv.writer(file_a)
reader2 = csv.reader(file_b)
next(reader2)
for row in reader2:
if (row[0], row[2]) not in removal_list:
# If row was not present in file B, Delete it from file A.
#stuck here: writer.<HowDoIRemoveRow>(row)
答案 0 :(得分:7)
此解决方案使用fileinput
和inplace=True
,它会写入临时文件,然后自动将其重命名为您的文件名。你不能从文件中删除行,但你可以只用你想要的那些重写它。
如果将关键字参数
inplace=1
传递给fileinput.input()
或FileInput
构造函数,则将文件移动到备份文件,并将标准输出定向到输入文件(如果是与备份文件同名的文件已经存在,它将被静默替换)。这使得编写一个可以重写其输入文件的过滤器成为可能。
的fileA
h1,h2,h3
a,b,c
d,e,f
g,h,i
j,k,l
FILEB
h1,h2,h3
a,b,c
1,2,3
g,h,i
4,5,6
import fileinput, sys, csv
with open('fileB', 'rb') as file_b:
r = csv.reader(file_b)
next(r) #skip header
seen = {(row[0], row[2]) for row in r}
f = fileinput.input('fileA', inplace=True) # sys.stdout is redirected to the file
print next(f), # write header as first line
w = csv.writer(sys.stdout)
for row in csv.reader(f):
if (row[0], row[2]) in seen: # write it if it's in B
w.writerow(row)
的fileA
h1,h2,h3
a,b,c
g,h,i
答案 1 :(得分:3)
CSV不是数据库格式。它作为一个整体进行读写。您无法删除中间的行。因此,在不创建第三个文件的情况下执行此操作的唯一方法是将文件完全读入内存,然后将其写出,而不会出现违规行。
但总的来说,最好使用第三个文件。
答案 2 :(得分:3)
正如Lennart所描述的那样,当您迭代它时,无法就地修改CSV文件。
如果您真的反对创建第三个文件,可能需要考虑使用带有StringIO的字符串缓冲区,这个想法是在内存中构建文件A的新所需内容。在脚本结束时,您可以在文件A上写入缓冲区的内容。
from cStringIO import StringIO
with open('fileB', 'rb') as file_b:
new_a_buf = StringIO()
writer = csv.writer(new_a_buf)
reader2 = csv.reader(file_b)
next(reader2)
for row in reader2:
if (row[0], row[2]) not in removal_list:
writer.writerow(row)
# At this point, the contents (new_a_buf) exist in memory
with open('fileA', 'wb') as file_a:
file_a.write(new_a_buf.getvalue())