Python StringIO Module from Scratch with Examples

You may know of Python’s pre-defined file handling functions and how they are used in reading, writing, deleting, and other operations on system files. Now let’s see what StringIO is about.

In some instances, data needs to be read or created in memory rather than in actual files seen by the Operating System. This is where the Python StringIO module comes into play.

Module Hierarchy

Python StringIO Module Hierarchy
Module Hierarchy

StringIO extends an abstract base class known as TextIOBase. It is a class that handles streams whose bytes are represented in text format. Furthermore, it deals with the encoding and decoding of strings. TextIOBase itself extends the base class IOBase. IOBase is the abstract base class for all the classes in io , therefore, being on top of the module hierarchy.

The io module is a part of the Python Standard Library. It handles various types of I/O such as text, binary, and raw I/O. Any objects from these types are known as file objects or streams, which will be used interchangeably in this article.

StringIO Objects and Files

A file object acts just like a regular file. It allows most of the standard File I/O operations. However, there is one important difference between them. Regular files are created and stored as a softcopy visible to the operating system. However, file objects are created in memory, which automatically means they can be handled quicker and more efficiently.

Here’s a scenario, say you have a logger that writes information onto a file, and you want to send the log output over the network. You can read the file and write its contents into the network, or you can write the log to a StringIO object and send it to the receiving network without using the file system at all.

Installing the Module

As of the latest Python 3.10.2, StringIO is included in the IO module of the Python Standard Library.

Importing Python StringIO from IO

from io import StringIO

Creating an File Object in StringIO

Let’s create a StringIO stream by passing a string to StringIO()

Creating StringIO object exampleObject bypassing string-type exampleString

from io import StringIO

exampleString = "Welcome to PythonPool :)"
exampleObject = StringIO(exampleString)

As we’ve already discussed, we can apply essential File I/O functions on StringIO objects. Furthermore, let’s look at a few relevant lines of code.

Reading Data

print(exampleObject.read())

#output - Welcome to PythonPool 🙂

Writing Data

Editing the Object and reading it from the beginning

exampleObject.write(" pythonpool.com")
exampleObject.seek(0) #making sure stream is read from beginning
print(exampleObject.read())

#output - Welcome to PythonPool : ) pythonpool.com

Important StringIO methods + Example Code

Despite a few file handling methods, there are other ones from the module itself that are equally crucial for you to know.

“Difference between ordinary and extraordinary is practice”.

Therefore, try these out side by side using our online Python interpreter here.

1. StringIO.seek() – This function is inherited from the abstract base class IOBase. You can pass an integer value, which will be the index from which it starts reading the stream.

exampleObject.seek(0) # Points the cursor to the index position 0
print(exampleObject.read()) # Starts reading everything from index 0
#output - Welcome to PythonPool 🙂 pythonpool.com

exampleObject.seek(22) # Points the cursor the to the index position 22
print(exampleObject.read()) # Starts reading everything from index 22
#output - 🙂 pythonpool.com

2. StringIO.getvalue() – This method is from the class StringIO itself. Upon calling, it returns a string that consists of all the data in the file object.

print(exampleObject.getvalue()) #returning str data from exampleObject 

#output - Welcome to PythonPool 🙂 pythonpool.com

3. StringIO.truncate() – Inherited from the abstract base class IOBase, This function is used to resize the stream. An integer value can be passed, which will indicate the index position at which the stream content will be removed from.

print(exampleObject.read())
exampleObject.truncate(7) #removes characters from index 7
print(exampleObject.read())

# Output -
# Welcome to PythonPool 🙂 pythonpool.com
# Welcome

4. StringIO.tell() – Also, being a part of the IOBase class, this function provides the current index position in the file object that Python is pointing to.

exampleObject.seek(12) # points towards the 12th index of the stream
print(exampleObject.tell()) 

#output - 12

5. StringIO.close() – This function is inherited in this module from IOBase. Running this will prevent any operations to the stream. Hence, it closes the file object. Any further attempts to operate will result in a ValueError . Re-running this function multiple times will not have any effect on the stream.

exampleObject.close()
print(exampleObject.read())

#output 
# ValueError: I/O operation on closed file

StringIO methods of bool return type:

All of these functions are inherited from the base class IOBase.

  1. StringIO.isatty() – Indicates whether a file object is interactive.
  2. StringIO.writable() – Returns a bool on the file object supporting writing.
  3. StringIO.readable() – States True or False on the file object being readable
  4. StringIO.seekable() – Returns a bool on the file object being allowed random access
  5. StringIO.closed() – Returns a bool on the file object being closed or not.

# Returns whether the file is interactive
print("Is the file object interactive?", exampleObject.isatty())
 
# Returns whether the file supports writing
print("Is the file object writable?", exampleObject.writable())

# Returns whether the file is readable
print("Is the file object readable?", exampleObject.readable())

# Returns whether the file is seekable
print("Is the file object seekable?", exampleObject.seekable())
 
# Returns whether the file object is closed or not
print("Is the file object closed?", exampleObject.closed)

Is it Possible to Write CSV using StringIO?

We already know that file objects act similar to files, and standard file I/O operations can be performed. The only difference is that the file objects are stored in memory. Therefore, writing files in CSV format shouldn’t be too difficult.

Let’s take a look at this code:

from io import StringIO
import csv

exampleObject = StringIO() #creating object
writeCSV = csv.writer(exampleObject)

# Writing the rows
writeCSV.writerows([["pythonpool", "stringIO","python"], 
                                      ["12", "23", "4"],
                                      ["#", "%^", "^&"]])
                             
# Setting the cursor to the beginning of the csv file object
exampleObject.seek(0)

# Creating an iteration to print the rows of the csv file
for eachRow in exampleObject:
     print(eachRow)


Why would this be of any use?

Let’s say we have to extract data online about the weather/climatic conditions of the USA and store relevant information onto a database. The standard procedure would be to download the data, unpack it, and add it to a CSV database. Therefore, with the help of modules like StringIO and CSV, we can automate such tasks, which would take up unnecessary time.

Differences between StringIO.StringIO and tempfile.TemporaryFile

StringIO.StringIOtempfile.TemporaryFile
Used to create a file object or a stream which is unlike regular files as it is stored in system memory.Used for storing data temporarily when large amounts of data are being handled during the program’s execution.
Upon closing, any further operations will result in an ValueError exception.Upon closing, any further operations will not be possible as they will be erased automatically.
File objects are stored in the memory randomly.Temp files are stored in directories that we can assign.

FAQs on Python StringIO

What’s the difference between Python StringIO and BytesIO?

Despite them both inheriting from the base class IOBase. StringIO is a part of the base class TextIOBase, and BytesIO is a part of BufferedIOBase. Therefore, StringIO is used for string data, whereas BytesIO deals with binary data. However, both of them are valuable modules to create file-like objects in memory.

How do we prevent a memory leak from Python StringIO?

We can, of course, use external modules such as Memory Profiler and use its built-in functions to track the memory consumption on how file objects are stored. But, simple optimizations like closing file objects after performing operations and deleting unwanted streams can go a long way in preventing memory-based exceptions.

Conclusion

We have looked at the components of the Python IO module that deal with the string datatype. Thereby, we learned various instances and use cases where the StringIO module and its inherited methods come together to handle string-type file objects efficiently.

Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments