2011-07-02 43 views
25

我想從標準輸入中讀取一個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) 

我寫代碼:

輸出 python test_writer.py | python test_reader.py
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) 

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毫秒的差距。

+0

如果你只運行'python test_writer.py',會發生什麼? –

回答

31

正如says in the documentation

爲了使一個for循環最有效的方式循環遍歷文件的行(非常常見)操作),next()方法使用隱藏的預讀緩衝區。

而且你可以通過查看the implementation of the csv module(線784),其csv.reader調用underlyling迭代的方法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

優秀的答案,謝謝。我需要這個的原因是因爲處理結果,因爲他們來了會提供給我速度。第一個操作是從網絡讀取數據,第二個操作是寫入磁盤,它們都需要某些CPU密集型轉換。此外,我需要它們可鏈接(通過管道)才能重新使用腳本(a la unix)。 – muhuk

0

你正在刷新標準輸出,但不是標準輸入。

Sys.stdin也有一個flush()方法,如果你真的想禁用緩衝,嘗試在每行讀後使用它。

+0

在'sys.stdin'上調用'flush()'沒有任何好處。 – muhuk

+4

如果downvoter留下了一些解釋,這將很酷。我真的很想知道*爲什麼*調用'stdin.flush()'沒有幫助。 – muhuk

1

也許這是一個限制。閱讀本http://docs.python.org/using/cmdline.html#cmdoption-unittest-discover-u

注意,有內部緩衝 在file.readlines()和文件對象 (在sys.stdin線),這是不是 此選項的影響。要圍繞此工作 ,您將希望在1: 循環內使用 file.readline()。

我改性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' 
+0

你說得對。但是,如何獲得'csv.reader'來利用這個黑客? – muhuk

相關問題