2012-04-17 9 views
9

Tôi muốn sử dụng luồng đệm vì tôi muốn sử dụng phương thức peek() để xem trước nhưng sử dụng luồng của tôi bằng một phương pháp khác dự kiến ​​một đối tượng giống như tệp. (Tôi muốn sử dụng seek() nhưng có thể phải xử lý đường ống trong I/O mà không hỗ trợ truy cập ngẫu nhiên.)python: sử dụng io.BufferedReader trên luồng thu được bằng open()?

Nhưng trường hợp thử nghiệm này không thành công:

AttributeError: 'file' đối tượng không có thuộc tính ' _checkReadable '

import sys 
import io 

srcfile = sys.argv[1] 
with open(srcfile, 'rb') as f: 
    fbuf = io.BufferedReader(f) 
    print fbuf.read(20) 

Điều gì đang xảy ra và cách khắc phục? Tôi nghĩ rằng BufferedReader được dự định để đệm một dòng. Nếu vậy, tại sao chức năng open() không trả về một cái gì đó tương thích với nó?

+0

Thật thú vị. Mặc dù chúng tôi có cùng phiên bản (2.7.x), chúng tôi nhận được thông báo lỗi hơi khác nhau. – username

+0

Tôi đã tìm thấy nó. Có một nhận xét trong io.py là "" "Các mô tả phương pháp và việc triển khai mặc định được kế thừa từ phiên bản C." "" Vì vậy, nó phụ thuộc vào các phiên bản c hoặc hệ điều hành. – username

+0

@username: Đây không phải là hệ điều hành cụ thể. Python của tôi 2.6.7 cũng phàn nàn về '_checkReadable', trong khi 2.7.2 của tôi phàn nàn về' readable'.Tôi không thể tìm thấy cam kết ngay bây giờ, nhưng điều này có lẽ đã thay đổi điều này ở đâu đó giữa 2.7.0 và 2.7.2. –

Trả lời

1

Bạn có thể thiết lập số lượng đệm trong byte bằng cách truyền buffering argument mở:

import sys 

srcfile = sys.argv[1] 
with open(srcfile, 'rb', buffering=30) as f: 
    print(f.peek(30)) 
    print(f.read(20)) 

Đây là một BufferedReader:

>>> with open("test.txt", 'rb', buffering=30) as f: 
...  type(f) 
<class '_io.BufferedReader'> 

Lưu ý rằng, theo mặc định, nó đệm để 1 - dòng đệm.

+0

chắc chắn, điều đó tốt , nhưng cuối cùng tôi sẽ muốn đệm xung quanh các nguồn khác của đầu vào có thể không được đệm ... hoặc là tất cả mọi thứ chỉ đệm theo mặc định? sys.stdin? luồng mạng? –

+0

Vâng, sau đó bạn có thể làm những gì bạn đã làm và làm '' BufferedReader (f) '' - vì nó đã là một '' BufferedReader'' nó sẽ làm việc. –

+1

Đây là giải pháp Python 3; trong Python 2 OP nên sử dụng 'io.open'. –

15

Bởi vẻ của tuyên bố print của bạn, bạn đang sử dụng Python 2. Trên phiên bản đó, một file không phải là một đối số hợp lệ để các nhà xây dựng BufferedReader:

Under Python 2.x, this is proposed as an alternative to the built-in file object, but in Python 3.x it is the default interface to access files and streams. (1)

Bạn nên sử dụng io.open thay vì:

>>> f = io.open(".bashrc", "rb") 

Nếu bạn làm điều này, không cần phải bọc nó một cách rõ ràng trong một BufferedReader vì đó chính xác là những gì io.open trả về theo mặc định:

>>> type(f) 
<type '_io.BufferedReader'> 

Xem its docs để biết chi tiết; có một đối số buffering kiểm soát bộ đệm.

Trong Python 3, open is io.open để hai thư viện I/O được hợp nhất lại thành một. Có vẻ như io đã được thêm vào Python 2.6 chủ yếu để tương thích về phía trước.

+0

+1 - đây là câu trả lời đúng cho 2.x –

+1

không cần phải bọc để mở tệp, nhưng nếu tôi sử dụng sys.stdin thì sao? –

+0

@ Jason: sau đó [hack] (http://stackoverflow.com/questions/6065173/making-io-bufferedreader-from-sys-stdin-in-python) mà 'tên người dùng' được chỉ định là hợp lệ. Hoặc 'io.open ("/dev/stdin ")' nếu nền tảng của bạn có tệp đó (nhưng trong cả hai trường hợp vẫn chưa rõ 'sys.stdin'). –

0

Trong python2, nếu bạn phải sử dụng file đối tượng như được trả về bởi open (hoặc ví dụ được cung cấp bởi một số thói quen mô-đun mà bạn không thể sửa đổi), bạn có thể sử dụng bộ mô tả tập tin thu được bằng cách fileno() cho io.FileIO constructor, sau đó vượt qua io.FileIO đối tượng để io.BufferedReader constructor.

Vì vậy, bạn mẫu mã có thể được viết lại như sau:

import sys 
import io 

srcfile = sys.argv[1] 
with open(srcfile, 'rb') as f: 
    fio = io.FileIO(f.fileno()) 
    fbuf = io.BufferedReader(fio) 
    print fbuf.read(20)