CSV Writer未关闭文件。

26

我正在读取一个CSV文件,然后写入一个新文件:

import csv

with open('thefile.csv', 'rb') as f:
  data = list(csv.reader(f))

import collections
counter = collections.defaultdict(int)
for row in data:
    counter[row[11]] += 1

writer = csv.writer(open('/pythonwork/thefile_subset1.csv', 'w'))
for row in data:
    if counter[row[11]] >= 500:
       writer.writerow(row)

出于某种原因,我无法让csv.writer关闭文件。当我打开文件时,它显示为只读,因为它仍然处于打开状态。

我完成后如何关闭thefile_subset1.csv?

6个回答

37
with open('/pythonwork/thefile_subset1.csv', 'w') as outfile:
    writer = csv.writer(outfile)
    for row in data:
        if counter[row[11]] >= 500:
           writer.writerow(row)

在不停地向CSV文件中写入数据直到出现KeyboardInterrupt时,这段代码对我来说无法正常工作。使用flush()方法可以解决这个问题。请查看我提供的答案 - Caglayan DOKME

25

你可以将打开命令分解为自己的变量,以便稍后可以关闭它。

f = open('/pythonwork/thefile_subset1.csv', 'w')
writer = csv.writer(f)
f.close()

csv.writer 如果尝试向已关闭的文件写入数据,则会引发 ValueError 异常。


2
最好使用另一个 with 语句,就像一开始读取数据时所使用的那样。 - Will McCutchen
同意。我自己也要养成使用with的习惯。 - Donald Miner

6

关闭文件,而不是 CSV 写入器。为此,您需要在实例化编写器之前先打开文件,而不是将所有内容都放在一行中。

import csv
import collections

with open('thefile.csv', 'rb') as f:
    data = list(csv.reader(f))

counter = collections.defaultdict(int)
for row in data:
    counter[row[11]] += 1

f.close()  # good idea to close if you're done with it

fSubset = open('/pythonwork/thefile_subset1.csv', 'w')
writer = csv.writer(fSubset)
for row in data:
    if counter[row[11]] >= 500:
        writer.writerow(row)

fSubset.close()

此外,我建议在脚本顶部保留您的导入,并在使用完第一个文件后关闭它。

1
f.close() 是不必要的。为什么不使用 with open 来处理 fSubset - user3657941
1
我正在使用一个类,该类使用(而不是扩展)csv writer,并且该writer在多个方法之间无限共享。 “with open as”模式并不适用于所有用例。确保有一种方法来清理打开的文件描述符对于长时间运行的进程非常重要。 - Jeff W

5

强制作者进行清理:

del writer

2
没有保证清理操作会立即执行(这取决于您使用的 Python 实现方式)。 - Greg Hewgill
2
del语句仅仅是删除名称绑定:“删除名称将从本地或全局命名空间中删除该名称的绑定,具体取决于该名称是否在同一代码块中的全局语句中出现。” 它并没有说明清理何时发生。 - Greg Hewgill
@James Roth,虽然这可能适用于CPython,但这是一个非常糟糕的想法。例如对于Jython它将不起作用,因为只有当writer被垃圾回收时才会被关闭。Python并没有说什么时候通过删除对writer的引用来关闭文件。更重要的是,这掩盖了意图,即关闭文件,这会影响可读性。 - John La Rooy
哦,天啊,詹姆斯,这真的是一个可怕的想法,确实很可怕。 - Alex Gordon
2
只有解决我的问题的答案才是有效的。其他答案都是事后诸葛亮(即这是你将来应该做的)。需要注意的是,你应该立即调用 gc.collect() 手动启动垃圾回收。 - Muhd
显示剩余2条评论

0

尽管它可能会降低应用程序的性能,但flush()也是解决此问题的一种方法。

with open("path/to/file.csv", "w", newline="") as csvFile:
    # ... do your things ...
    # ... write to the CSV file ...
       
    csvFile.flush()

你可以在编写循环结束时或每次调用 writerow(..) 方法后调用它。在我的情况下,除非程序终止,我会不断将数据写入 CSV 文件,这是唯一可行的解决方案。

顺便说一下,如果你想知道是什么导致了这种情况,最好看一下你的操作系统的文件缓存方法。实际上,这是由一个缓冲机制引起的,旨在提高计算机的文件 I/O 性能。


-2

看看它们的不同之处:

with open('thefile.csv', 'rb') as f:
    data = list(csv.reader(f))

对比:

writer = csv.writer(open('/pythonwork/thefile_subset1.csv', 'w'))

8
那么答案是什么?这很令人困惑。 - Alex Gordon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接