Использование io.BufferedReader в потоке, полученном с помощью open()?

Я хочу использовать буферизованный поток, потому что я хочу использовать метод peek() для просмотра вперед, но использовать мой поток с другим методом, который ожидает файлоподобный объект. (Я бы использовал seek(), но, возможно, придется обрабатывать конвейерный ввод-вывод, который не поддерживает произвольный доступ.)

Но этот тестовый пример терпит неудачу:

AttributeError: объект «файл» не имеет атрибута «_checkReadable»

import sys
import io

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

Что происходит и как это исправить? Я думал, что BufferedReader предназначен для буферизации потока. Если да, то почему функция open() не возвращает что-то совместимое с ней?


person Jason S    schedule 17.04.2012    source источник
comment
Это интересно. Хотя у нас одинаковые версии (2.7.x), мы получаем немного разные сообщения об ошибках.   -  person username    schedule 18.04.2012
comment
Я узнал это. Однако в io.py есть комментарий, поскольку описания методов и реализации по умолчанию унаследованы от версии C. Так что это зависит от версии c или ОС.   -  person username    schedule 18.04.2012
comment
@username: это не зависит от ОС. Мой Python 2.6.7 также жалуется на _checkReadable, а мой 2.7.2 жалуется на readable. Я не могу найти фиксацию прямо сейчас, но, вероятно, это было изменено где-то между 2.7.0 и 2.7.2.   -  person Fred Foo    schedule 18.04.2012
comment
возможный дубликат Создание io.BufferedReader из sys.stdin в Python   -  person Jason S    schedule 18.04.2012


Ответы (3)


Судя по вашему выражению print, вы используете Python 2. В этой версии file не является допустимым аргументом для конструктора BufferedReader:

В Python 2.x это предлагается в качестве альтернативы встроенному объекту file, но в Python 3.x это интерфейс по умолчанию для доступа к файлам и потокам. (1)

Вместо этого вы должны использовать io.open:

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

Если вы сделаете это, нет необходимости явно оборачивать его в BufferedReader, так как это именно то, что io.open возвращает по умолчанию:

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

Подробнее см. в документах; есть аргумент buffering, который управляет буферизацией.

В Python 3 open is io.open две библиотеки ввода-вывода были объединены обратно в одну. Похоже, что io был добавлен в Python 2.6 в основном для совместимости с предыдущими версиями.

person Fred Foo    schedule 17.04.2012
comment
нет необходимости обертывать для открытия файла, но что, если вместо этого я использую sys.stdin? - person Jason S; 18.04.2012
comment
@JasonS: тогда хак, на который указал username, действителен . Или io.open("/dev/stdin"), если на вашей платформе есть этот файл (но в любом случае держитесь подальше от sys.stdin). - person Fred Foo; 18.04.2012

Вы можете установить объем буферизации в байтах, передав buffering аргумент для открытия:

import sys

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

Это BufferedReader:

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

Обратите внимание, что по умолчанию он буферизуется до 1 — строки буферизуются.

person Gareth Latty    schedule 17.04.2012
comment
конечно, это нормально, но в конечном итоге я захочу буферизовать другие источники ввода, которые могут не буферизоваться... или все просто буферизуется по умолчанию? sys.stdin? сетевые потоки? - person Jason S; 18.04.2012
comment
Что ж, тогда вы можете сделать то, что вы сделали, и сделать BufferedReader(f) - поскольку это уже BufferedReader, это сработает. - person Gareth Latty; 18.04.2012
comment
Это решение Python 3; в Python 2 ОП должен использовать io.open. - person Fred Foo; 18.04.2012
comment
@larsmans Ах, я не знал, что это функция 3.x, вы правы. - person Gareth Latty; 18.04.2012
comment
Исправление: на самом деле это довольно правильное решение и в Python 2, но open вернет file, а не BufferedReader в 2.x, поэтому метода peek нет. - person Fred Foo; 18.04.2012

В Python2, если вам нужно использовать объект file, возвращенный open (или, например, предоставленный некоторыми подпрограммами модуля, которые вы не можете изменить), вы можете использовать файловый дескриптор, полученный fileno() для конструктора io.FileIO, а затем передать объект io.FileIO конструктору io.BufferedReader.

Итак, ваш пример кода можно переписать следующим образом:

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)
person majkelx    schedule 29.06.2016