2011-07-02 35 views
25

Tôi muốn đọc tệp CSV từ đầu vào tiêu chuẩn và xử lý từng hàng khi nó đến. Mã xuất CSV của tôi viết từng hàng một, nhưng trình đọc của tôi chờ luồng được chấm dứt trước khi lặp lại các hàng. Đây có phải là giới hạn của mô-đun csv không? Tôi có làm điều gì sai?Cách đọc tệp CSV từ luồng và xử lý từng dòng như được viết?

đang đọc của tôi:

import csv 
import sys 
import time 


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

đang nhà văn của tôi:

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) 

Sản lượng 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', '$$$$$$$$'] 

Như bạn có thể thấy tất cả các báo cáo in được thực hiện cùng một lúc , nhưng tôi mong đợi có khoảng cách 500ms.

+0

Điều gì sẽ xảy ra nếu bạn chỉ chạy 'python test_writer.py'? –

Trả lời

31

Vì nó says in the documentation,

Để thực hiện một vòng lặp for cách hiệu quả nhất looping trên các dòng của một tập tin (một rất phổ biến hoạt động), phương pháp next() sử dụng bộ đệm ẩn trước.

Và bạn có thể nhìn thấy bằng cách nhìn vào the implementation of the csv module (dòng 784) mà csv.reader gọi phương thức next() của iterator underlyling (thông qua PyIter_Next). Vì vậy, nếu bạn thực sự muốn đọc không đọc các tệp CSV, bạn cần phải chuyển đổi đối tượng tệp (tại đây sys.stdin) thành một trình lặp có phương thức next() thực sự gọi số readline() thay thế. Điều này có thể dễ dàng được thực hiện bằng cách sử dụng dạng hai đối số của hàm iter.Vì vậy, thay đổi mã trong test_reader.py một cái gì đó như thế này:

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

Ví dụ,

$ 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] 

bạn có thể giải thích lý do tại sao bạn cần đọc unbuffered các tập tin CSV? Có thể có một giải pháp tốt hơn cho bất cứ điều gì bạn đang cố gắng làm.

+1

Câu trả lời hay, cảm ơn bạn. Lý do tôi cần điều này là bởi vì việc xử lý các kết quả khi họ đến sẽ cung cấp cho tôi tốc độ. Hoạt động đầu tiên được đọc từ mạng và hoạt động thứ hai là ghi vào đĩa và cả hai đều cần một số bản dịch chuyên sâu của CPU. Ngoài ra tôi cần chúng để được chainable (thông qua đường ống) để có thể tái sử dụng các kịch bản (a la unix). – muhuk

0

Bạn đang bung ra stdout nhưng không phải stdin.

Sys.stdin cũng có phương thức flush(), hãy thử sử dụng sau mỗi dòng đọc nếu bạn thực sự muốn vô hiệu hóa bộ đệm.

+0

Gọi 'flush()' trên 'sys.stdin' không thực hiện tốt. – muhuk

+4

Nó sẽ được mát mẻ nếu downvoter để lại một chút giải thích. Tôi thực sự muốn biết * tại sao * gọi 'stdin.flush()' không giúp ích gì. – muhuk

1

Có thể đó là hạn chế. Đọc http://docs.python.org/using/cmdline.html#cmdoption-unittest-discover-u

Lưu ý rằng có nội đệm trong file.readlines() và File Objects (đối với dòng trong sys.stdin) mà không phải là ảnh hưởng bởi tùy chọn này. Để làm việc xung quanh điều này, bạn sẽ muốn sử dụng tệp.readline() trong một khoảng thời gian 1: vòng lặp.

tôi sửa đổi test_reader.py như sau:

import csv, sys, time 

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

Output

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

Bạn nói đúng. Nhưng làm thế nào để tôi nhận được 'csv.reader' để tận dụng lợi thế của hack này? – muhuk

Các vấn đề liên quan