The io module in the standard library provides functions and classes for handling input and output operations. In this article we will focus on the BytesIO class.

The BytesIO class is used for creating in-memory byte streams that can be used as a file object. The created BytesIO object( commonly reffered to as a stream) has a file-like API, with methods like read() write(), readlines() and other file methods. 

To use the class we will first need to import it in our program, as shown below:

ExampleEdit & Run
from io import BytesIO #import the class

print(BytesIO)
copy
Output:
<class '_io.BytesIO'> [Finished in 0.01053861016407609s]

Basic Usage

The BytesIO constructor has the following syntax:

Syntax:
BytesIO(initial_bytes = b'')
copy

The initial_bytes parameter specifies the initial bytes contents of the created BytesIO object. If initial_bytes is not given, an empty BytesIO will be created.

ExampleEdit & Run

initialize a BytesIO object

from io import BytesIO

data = b'Hello, World'
stream = BytesIO(data)

print(stream.getvalue()) #read from the stream

stream.close()
copy
Output:
b'Hello, World' [Finished in 0.010051120072603226s]

In the above example we created a bytes stream with initial bytes data, the b prefix indicates that the string should be treated as a bytes literal rather than a regular string. 

The stream.getvalue() method returns the entire contents of the bytes stream as a bytes object.

After calling the close() method, the stream cannot be read from or written to. We can automate calling of this method by using the ByteIO object as a context manager i.e using with statement. This way the above example will look as follows:

ExampleEdit & Run
from io import BytesIO

data = b'Hello, World'

with BytesIO(data) as stream:
     print(stream.getvalue()) #read from the stream

#the stream is now closed.
copy
Output:
b'Hello, World' [Finished in 0.01074271323159337s]

Reading and Writing bytes data

We can perform various operations on the BytesIO stream, just like we would on a regular file object. 

reading bytes

The read() method to reads and returns a specified number of bytes from the stream starting from the current position of the stream "cursor".

ExampleEdit & Run

use read() to read from the stream

from io import BytesIO

data = b'Hello, World!'

with BytesIO(data) as stream:
    stream = BytesIO(data)
    stream.seek(0)

    print(stream.read(5)) #read 5 bytes from the stream
copy
Output:
b'Hello' [Finished in 0.010181364137679338s]

Note that in the above example, before calling the read() method, we first called the seek() method which moves the current position in the file to the beginning (position 0). This ensures that when we call the read() method, it will start reading the file from the beginning. Otherwise, it would start reading from wherever the 'cursor' position is, which in the above case is in the end of the file.

The readline() methods reads bytes until it meets the end of line character. Consider the following example:

ExampleEdit & Run
from io import BytesIO

data = b"Hello, World!\nWelcome to Pynerds."

with BytesIO(data) as stream:
    stream.seek(0)

    print('line1: ', stream.readline()) #reads a single line
    print('line2: ', stream.readline()) #reads another line
copy
Output:
line1:  b'Hello, World!\n' line2:  b'Welcome to Pynerds.' [Finished in 0.010291392914950848s]

To read multiple lines at once , we can use the readlines() method, which returns a list  of all lines in the stream starting from the position of the "cursor".

ExampleEdit & Run
from io import BytesIO

data = b"Hello, World!\nWelcome to Pynerds."
stream = BytesIO(data)

stream.seek(0)
print(stream.readlines()) #read all lines
copy
Output:
[b'Hello, World!\n', b'Welcome to Pynerds.'] [Finished in 0.009632996749132872s]

Writing to the stream

The write() method writes the specified bytes  into the stream, starting from the current point of the "cursor". It has the following syntax:

Syntax:
stream.write(data)
copy
ExampleEdit & Run

write to the stream

from io import BytesIO

with BytesIO() as stream:
     stream.write(b'Hello, World!\n')
     stream.write(b'Welcome to Pynerds.')
     
     print(stream.getvalue()) #get the contents
copy
Output:
b'Hello, World!\nWelcome to Pynerds.' [Finished in 0.009532521944493055s]

To write multiple lines at once you can use the writelines() method. The method takes an iterable containing the lines of bytes to be written.

ExampleEdit & Run
from io import BytesIO

lines = [b'Hello, World\n', b'Welcome to Pynerds']

with BytesIO() as stream:
     stream.writelines(lines)
     
     print(stream.getvalue()) #get the contents
copy
Output:
b'Hello, World\nWelcome to Pynerds' [Finished in 0.009790841955691576s]

Note that the writelines() method does not add the end of line character between the lines, you have to do that yourself.

Other BytesIO methods and attributes

In addition to the methods we have discussed, BytesIO objects contains other methods, some of them are shown in the following table:

readable() Returns True if the BytesIO stream can be read from. Otherwise False.
seekable() Returns True if the stream can be seeked. Otherwise False
writable() Returns True if the stream can be written to. Otherwise False.
seek() Change the positions of the stream 'cursor' to the specified position. Defaults to 0, which is the beginning of the stream.
tell() Returns the current position of the stream 'cursor'.
truncate() Truncate the stream to a given size.