Using io.BufferedReader on a stream obtained with open()?

Jason S picture Jason S · Apr 17, 2012 · Viewed 57.6k times · Source

I want to use a buffered stream because I want to use a peek() method to peek ahead but use my stream with another method that expects a file-like object. (I'd use seek() but may have to handle piped-in I/O that doesn't support random access.)

But this test case fails:

AttributeError: 'file' object has no attribute '_checkReadable'

import sys
import io

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

What's going on and how do I fix it? I thought BufferedReader was intended to buffer a stream. If so, why does the open() function not return something that's compatible with it?

Answer

Fred Foo picture Fred Foo · Apr 17, 2012

By the looks of your print statement, you're using Python 2. On that version, a file is not a valid argument to the BufferedReader constructor:

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)

You should use io.open instead:

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

If you do this, there's no need to explicitly wrap it in a BufferedReader since that's exactly what io.open returns by default:

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

See its docs for details; there's a buffering argument that controls the buffering.

In Python 3, open is io.open so the two I/O libraries have been merged back into one. It seems io was added to Python 2.6 mostly for forward compatibility.