如何从流中读取CSV文件并在写入时处理每一行?

时间:2011-07-02 09:08:09

标签: python csv stream line-by-line

我想从标准输入读取一个CSV文件,并在每一行处理它们。我的CSV输出代码逐个写入行,但我的读者在迭代行之前等待流终止。这是csv模块的限制吗?我做错了吗?

我的读者代码:

import csv
import sys
import time


reader = csv.reader(sys.stdin)
for row in reader:
    print "Read: (%s) %r" % (time.time(), row)

我的作家代码:

import csv
import sys
import time


writer = csv.writer(sys.stdout)
for i in range(8):
    writer.writerow(["R%d" % i, "$" * (i+1)])
    sys.stdout.flush()
    time.sleep(0.5)

python test_writer.py | python test_reader.py的输出:

Read: (1309597426.3) ['R0', '$']
Read: (1309597426.3) ['R1', '$$']
Read: (1309597426.3) ['R2', '$$$']
Read: (1309597426.3) ['R3', '$$$$']
Read: (1309597426.3) ['R4', '$$$$$']
Read: (1309597426.3) ['R5', '$$$$$$']
Read: (1309597426.3) ['R6', '$$$$$$$']
Read: (1309597426.3) ['R7', '$$$$$$$$']

正如您所看到的所有打印报表同时执行,但我预计会有500毫秒的差距。

3 个答案:

答案 0 :(得分:32)

正如says in the documentation

  

为了使for循环成为循环文件行的最有效方式(一种非常常见的操作),next()方法使用隐藏的预读缓冲区。

您可以通过查看the implementation of the csv module(第784行)看到csv.reader调用底层迭代器的next()方法(通过PyIter_Next)。

因此,如果您真的想要无缓冲读取CSV文件,则需要将文件对象(此处为sys.stdin)转换为其next()方法实际调用readline()的迭代器。这可以使用iter函数的双参数形式轻松完成。因此,将test_reader.py中的代码更改为以下内容:

for row in csv.reader(iter(sys.stdin.readline, '')):
    print("Read: ({}) {!r}".format(time.time(), row))

例如,

$ python test_writer.py | python test_reader.py
Read: (1388776652.964925) ['R0', '$']
Read: (1388776653.466134) ['R1', '$$']
Read: (1388776653.967327) ['R2', '$$$']
Read: (1388776654.468532) ['R3', '$$$$']
[etc]

您能解释为什么需要无缓冲读取CSV文件吗?无论你想做什么,都可能有更好的解决方案。

答案 1 :(得分:1)

也许这是一个限制。阅读此http://docs.python.org/using/cmdline.html#cmdoption-unittest-discover-u

  

请注意,有内部缓冲   在file.readlines()和文件对象中   (对于sys.stdin中的行)不是   受此选项的影响。上班   在此周围,你会想要使用   file.readline()在一段时间内1:   循环。

我修改了test_reader.py,如下所示:

import csv, sys, time

while True:
    print "Read: (%s) %r" % (time.time(), sys.stdin.readline())

输出

python test_writer.py | python  test_reader.py
Read: (1309600865.84) 'R0,$\r\n'
Read: (1309600865.84) 'R1,$$\r\n'
Read: (1309600866.34) 'R2,$$$\r\n'
Read: (1309600866.84) 'R3,$$$$\r\n'
Read: (1309600867.34) 'R4,$$$$$\r\n'
Read: (1309600867.84) 'R5,$$$$$$\r\n'
Read: (1309600868.34) 'R6,$$$$$$$\r\n'
Read: (1309600868.84) 'R7,$$$$$$$$\r\n'

答案 2 :(得分:0)

你正在冲洗stdout,但不是stdin。

Sys.stdin也有flush()方法,如果你真的想要禁用缓冲,请尝试在每行读取后使用它。