Подтвердить что ты не робот

Как читать CSV файл из потока и обрабатывать каждую строку, когда она написана?

Я хотел бы прочитать 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 мс.

4b9b3361

Ответ 1

Как говорится в в документации,

Чтобы сделать цикл for наиболее эффективным способом петли над строками файла (очень распространенная операция), метод next() использует скрытый буфер чтения.

И вы можете увидеть, посмотрев реализацию модуля csv (строка 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 файлов? Возможно, будет лучшее решение того, что вы пытаетесь сделать.

Ответ 2

Возможно, это ограничение. Прочтите это http://docs.python.org/using/cmdline.html#cmdoption-unittest-discover-u

Обратите внимание, что есть внутренняя буферизация в файлах file.readlines() и File Objects (для строки в 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'

Ответ 3

Вы очищаете stdout, но не stdin.

Sys.stdin также имеет метод flush(), попробуйте использовать это после каждой строки, если вы действительно хотите отключить буферизацию.