For simplicity's sake, let's consider writing instead of reading for now.

So when you use open() like say:

with open("test.dat", "wb") as f:
    f.write(b"Hello World")
    f.write(b"Hello World")
    f.write(b"Hello World")

After executing that a file called test.dat will be created, containing 3x Hello World. The data wont be kept in memory after it's written to the file (unless being kept by a name).

Now when you consider io.BytesIO() instead:

with io.BytesIO() as f:
    f.write(b"Hello World")
    f.write(b"Hello World")
    f.write(b"Hello World")

Which instead of writing the contents to a file, it's written to an in memory buffer. In other words a chunk of RAM. Essentially writing the following would be the equivalent:

buffer = b""
buffer += b"Hello World"
buffer += b"Hello World"
buffer += b"Hello World"

In relation to the example with the with statement, then at the end there would also be a del buffer.

The key difference here is optimization and performance. io.BytesIO is able to do some optimizations that makes it faster than simply concatenating all the b"Hello World" one by one.

Just to prove it here's a small benchmark:

  • Concat: 1.3529 seconds
  • BytesIO: 0.0090 seconds

import io
import time

begin = time.time()
buffer = b""
for i in range(0, 50000):
    buffer += b"Hello World"
end = time.time()
seconds = end - begin
print("Concat:", seconds)

begin = time.time()
buffer = io.BytesIO()
for i in range(0, 50000):
    buffer.write(b"Hello World")
end = time.time()
seconds = end - begin
print("BytesIO:", seconds)

Besides the performance gain, using BytesIO instead of concatenating has the advantage that BytesIO can be used in place of a file object. So say you have a function that expects a file object to write to. Then you can give it that in-memory buffer instead of a file.

The difference is that open("myfile.jpg", "rb") simply loads and returns the contents of myfile.jpg; whereas, BytesIO again is just a buffer containing some data.

Since BytesIO is just a buffer - if you wanted to write the contents to a file later - you'd have to do:

buffer = io.BytesIO()
# ...
with open("test.dat", "wb") as f:
    f.write(buffer.getvalue())

Also, you didn't mention a version; I'm using Python 3. Related to the examples: I'm using the with statement instead of calling f.close()

Answer from vallentin on Stack Overflow
🌐
ProgramCreek
programcreek.com › python › example › 1734 › io.BytesIO
Python Examples of io.BytesIO
Example #1 · def _deserialize(self, data, type_): if self.compress: # decompress the data if needed data = lz4.frame.decompress(data) if type_ == _NUMPY: # deserialize numpy arrays buf = io.BytesIO(data) data = np.load(buf) elif type_ == _PICKLE: # deserialize other python objects data = pickle.loads(data) else: # Otherwise we just return data as it is (bytes) pass return data ·
🌐
DigitalOcean
digitalocean.com › community › tutorials › python-io-bytesio-stringio
Python io.BytesIO and io.StringIO: Memory File Guide | DigitalOcean
August 3, 2022 - Use Python io.BytesIO and io.StringIO for in-memory operations. Complete guide with examples for binary, string data handling and performance tips.
Top answer
1 of 2
208

For simplicity's sake, let's consider writing instead of reading for now.

So when you use open() like say:

with open("test.dat", "wb") as f:
    f.write(b"Hello World")
    f.write(b"Hello World")
    f.write(b"Hello World")

After executing that a file called test.dat will be created, containing 3x Hello World. The data wont be kept in memory after it's written to the file (unless being kept by a name).

Now when you consider io.BytesIO() instead:

with io.BytesIO() as f:
    f.write(b"Hello World")
    f.write(b"Hello World")
    f.write(b"Hello World")

Which instead of writing the contents to a file, it's written to an in memory buffer. In other words a chunk of RAM. Essentially writing the following would be the equivalent:

buffer = b""
buffer += b"Hello World"
buffer += b"Hello World"
buffer += b"Hello World"

In relation to the example with the with statement, then at the end there would also be a del buffer.

The key difference here is optimization and performance. io.BytesIO is able to do some optimizations that makes it faster than simply concatenating all the b"Hello World" one by one.

Just to prove it here's a small benchmark:

  • Concat: 1.3529 seconds
  • BytesIO: 0.0090 seconds

import io
import time

begin = time.time()
buffer = b""
for i in range(0, 50000):
    buffer += b"Hello World"
end = time.time()
seconds = end - begin
print("Concat:", seconds)

begin = time.time()
buffer = io.BytesIO()
for i in range(0, 50000):
    buffer.write(b"Hello World")
end = time.time()
seconds = end - begin
print("BytesIO:", seconds)

Besides the performance gain, using BytesIO instead of concatenating has the advantage that BytesIO can be used in place of a file object. So say you have a function that expects a file object to write to. Then you can give it that in-memory buffer instead of a file.

The difference is that open("myfile.jpg", "rb") simply loads and returns the contents of myfile.jpg; whereas, BytesIO again is just a buffer containing some data.

Since BytesIO is just a buffer - if you wanted to write the contents to a file later - you'd have to do:

buffer = io.BytesIO()
# ...
with open("test.dat", "wb") as f:
    f.write(buffer.getvalue())

Also, you didn't mention a version; I'm using Python 3. Related to the examples: I'm using the with statement instead of calling f.close()

2 of 2
42

Using open opens a file on your hard drive. Depending on what mode you use, you can read or write (or both) from the disk.

A BytesIO object isn't associated with any real file on the disk. It's just a chunk of memory that behaves like a file does. It has the same API as a file object returned from open (with mode r+b, allowing reading and writing of binary data).

BytesIO (and it's close sibling StringIO which is always in text mode) can be useful when you need to pass data to or from an API that expect to be given a file object, but where you'd prefer to pass the data directly. You can load your input data you have into the BytesIO before giving it to the library. After it returns, you can get any data the library wrote to the file from the BytesIO using the getvalue() method. (Usually you'd only need to do one of those, of course.)

🌐
GeeksforGeeks
geeksforgeeks.org › python › stringio-and-bytesio-for-managing-data-as-file-object
Stringio And Bytesio For Managing Data As File Object - GeeksforGeeks
July 24, 2025 - This makes it convenient for managing binary data in-memory without the need for actual files. In this example, a new BytesIO object named binary_buffer is created to emulate an in-memory file for binary data.
🌐
Code-learner
code-learner.com › home › python stringio and bytesio example
Python StringIO And BytesIO Example ·
March 21, 2021 - BytesIO implements read and write bytes data in memory. We create a BytesIO object and then write some bytes data into it.
🌐
GeeksforGeeks
geeksforgeeks.org › python-stringio-and-bytesio-compared-with-open
Python Stringio and Bytesio Compared With Open() - GeeksforGeeks
March 28, 2024 - Hello, world! This is a StringIO with open() example. BytesIO, also in the io module, is similar to StringIO but operates on bytes objects, not strings.BytesIO class is commonly used for binary data manipulation in memory, such as processing image data or handling binary files.
🌐
Confessions of a Data Guy
confessionsofadataguy.com › home › you have to try this… from io import stringio, bytesio
You Have to Try This... from io import StringIO, BytesIO - Confessions of a Data Guy
January 2, 2021 - Really what I’m showing you here ... use in Python can take a file like object, in this example with ZipFile(in_memory_zip) as zippy, doesn’t matter if it’s an actual file sitting your disk, or a file like object sitting in memory. I feel like that’s enough for you to get started with StringIO and BytesIO...
🌐
Andrew Wheeler
andrewpwheeler.com › 2022 › 11 › 02 › using-io-objects-in-python-to-read-data
Using IO objects in python to read data | Andrew Wheeler
November 2, 2022 - # Example 2, grabbing zipped contents import zipfile from io import BytesIO census_url = 'https://www2.census.gov/programs-surveys/acs/summary_file/2019/data/2019_5yr_Summary_FileTemplates.zip' req = requests.get(census_url) # Can use BytesIO for this content zf = zipfile.ZipFile(BytesIO(req.content))
Find elsewhere
🌐
Reddit
reddit.com › r/learnpython › vs
r/learnpython on Reddit: <class 'bytes'> vs <class '_io.BytesIO'>
December 1, 2022 -

Hello all,

I'm trying to wrap my head around the practical differences between:

<class 'bytes'> and <class '_io.BytesIO'>.

I read through the documentation:

https://docs.python.org/3/library/io.html?highlight=bytesio#binary-i-o

Binary I/O (also called buffered I/O) expects bytes-like objects and produces bytes objects. No encoding, decoding, or newline translation is performed. This category of streams can be used for all kinds of non-text data, and also when manual control over the handling of text data is desired.

It provides some examples:

The easiest way to create a binary stream is with open() with 'b' in the mode string:

and

f = io.BytesIO(b"some initial binary data: \x00\x01")

So I read all this, but so what? Why would you use the io.BytesIO data type over a standard bytes data type?

EDIT: Let me provide some additional context that I just discovered after reading the documentation on lxml.

https://lxml.de/parsing.html#parsing-html

I'm using the requests object and parsing the results with lxml. Here is the example code:

from io import BytesIO
from lxml import etree
#* etree - https://lxml.de/parsing.html
#? etree stands for element tree

import requests

#? Need to know concepts
#?  What are bytes
#?  HTTP status codes
#?  HTTP methods (GET. POST, PUT, DELETE)
#?  bytes - https://docs.python.org/3/library/stdtypes.html?highlight=bytes#bytes-objects

url = 'http://localhost'
#! The URL https://nostarch.com/ doesn't seem to work

resp = requests.get(url=url)
html_bytes = resp.content
parser = etree.HTMLParser()
content = etree.parse(BytesIO(html_bytes), parser=parser)

print(type(html_bytes))
print(type(BytesIO(html_bytes)))

for link in content.findall('//a'):
    print(f"{link.get('href')} -> {link.text}")

Kind regards

🌐
Mellowd
mellowd.dev › posts › using-io-bytesio
Using io.BytesIO() with Python | mellowd.dev
May 16, 2019 - In this example I’ll create a graph in matplotlib and just save to a virtual file. #!/usr/bin/env python3 import io import matplotlib import matplotlib.pyplot as plt import numpy as np t = np.arange(0.0, 2.0, 0.01) s = 1 + np.sin(2 * np.pi * t) fig, ax = plt.subplots() ax.plot(t, s) ...
🌐
Learning Machine
gallon.me › using-the-bytesio-class-in-python
Using the BytesIO Class in Python - Learning Machine
February 14, 2025 - import io from PIL import Image # Pillow library for image processing # Simulated image bytes (normally you'd get this from a request) image_bytes = b'...' # Replace with actual image bytes # Wrap the bytes in a BytesIO object image_stream = io.BytesIO(image_bytes) # Open the image using PIL, which expects a file-like object image = Image.open(image_stream) image.show() # Display the image
🌐
Pynerds
pynerds.com › io-bytesio-in-python
io.BytesIO in Python
Disclaimer: References to any specific company, product or services on this Site are not controlled by GoDaddy.com LLC and do not constitute or imply its association with or endorsement of third party advertisers
🌐
Python Assets
pythonassets.com › posts › what-is-io-bytesio-useful-for
What Is `io.BytesIO` Useful For? | Python Assets
July 19, 2024 - And io.BytesIO supports these methods! Hence this will store an Excel of products in memory: This could be really helpful if we want, for example, to retrieve the contents of the Excel file in an HTTP endpoint. We can easily do that with Flask: Save this code as endpoint.py and run python endpoint.py, and we will have a simple web service that triggers the download of the products table as an Excel file at http://127.0.0.1:5000/. This way, we don't need to store the Excel file in the disk in order to retrieve it in a web response.
🌐
Webkul
webkul.com › home › python: using stringio and bytesio for managing data as file object
Python: Using StringIO and BytesIO for managing data as file object - Webkul Blog
October 1, 2019 - In Python 2.7 StringIO module was capable handling the Byte as well Unicode But in python3 you will have to use separate BytesIO for handling Byte strings and StringIO for handling Unicode strings.
🌐
TechOverflow
techoverflow.net › 2019 › 07 › 24 › how-to-write-bytesio-content-to-file-in-python
How to write BytesIO content to file in Python | TechOverflow
July 14, 2026 - """ with open(filename, "wb") as outfile: # Copy the BytesIO stream to the output file outfile.write(bytesio.getbuffer()) ... #!/usr/bin/env python3 from io import BytesIO import shutil # Initialie our BytesIO myio = BytesIO() myio.write(b"Test 123") def write_bytesio_to_file(filename, bytesio): """ Write the contents of the given BytesIO to a file.
🌐
Plain English
python.plainenglish.io › how-to-use-io-stringio-and-io-bytesio-in-python-c7e10c3180b8
How to use io.StringIO and io.BytesIO in Python | by Lynn G. Kwong | Python in Plain English
November 1, 2024 - In this example, we have a function that handles file upload. To test if this function is working properly in unit tests, we can simulate a file-like object with BytesIO and use it to test the target function.
🌐
AskPython
askpython.com › python-modules › python-io-module
Python IO Module: The Complete Practical Reference - AskPython
June 24, 2020 - To understand more about this module, let’s take some examples. This module is a part of the standard library, so there’s no need to install it separately using pip. ... We can access these classes using io.BytesIO and io.StringIO.