Unicode UTF-8 reading and writing to files in Python
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
In Python 3, text strings are Unicode, but files on disk are bytes. Reading and writing UTF-8 correctly is therefore about making the text-to-bytes conversion explicit, so Python does not guess the wrong encoding from the operating system or runtime defaults.
Writing UTF-8 Text Explicitly
The safest pattern is to pass encoding="utf-8" whenever you open a text file.
This tells Python exactly how to encode the Unicode string into bytes before writing to disk. It also makes the code more portable because the behavior does not depend on the platform's default text encoding.
Reading UTF-8 Text Back
Use the same explicit encoding when reading:
If the file really is UTF-8 encoded, this gives you back a normal Python str containing Unicode text.
Why Explicit Encoding Matters
If you omit the encoding, Python may use a platform-dependent default. On some systems that default happens to be UTF-8, but relying on that makes bugs intermittent and environment-specific.
The result can be:
- decoding errors on one machine but not another
- corrupted characters after writing
- files that appear fine in one editor and broken in another
Explicit encoding removes that ambiguity.
Handling Invalid Data
Sometimes the file is supposed to be UTF-8 but contains bad bytes. In that case, you can decide how strict you want Python to be with the errors parameter.
Common choices are:
- '
errors="strict"for fail-fast behavior' - '
errors="replace"to substitute invalid bytes with a replacement character' - '
errors="ignore"to skip invalid bytes, though that can silently lose data'
For debugging or data-cleaning work, replace is often safer than ignore because it preserves the fact that something went wrong.
Using pathlib
pathlib provides the same functionality with a more modern file API.
This is especially nice in scripts that already use Path objects heavily.
Text Mode vs Binary Mode
If you open a file in binary mode, Python gives you bytes and does not perform any encoding or decoding for you.
Binary mode is appropriate when you want direct control over the byte representation. Text mode with encoding="utf-8" is simpler when the file is plain text.
Common Pitfalls
The biggest pitfall is assuming Unicode and UTF-8 are the same thing. Unicode is the character model; UTF-8 is one byte encoding for storing Unicode text.
Another common mistake is omitting the encoding argument and hoping the system default is correct. That can work on your machine and fail elsewhere with no code changes.
Developers also misuse errors="ignore" as a quick fix. It hides encoding problems by dropping data, which is often worse than getting a visible exception.
Summary
- In Python 3, strings are Unicode, but files store bytes.
- Use
open(..., encoding="utf-8")to read and write UTF-8 text explicitly. - Add an
errorsstrategy when the input may contain invalid bytes. - Use binary mode only when you want manual control over encoding and decoding.
- Explicit UTF-8 handling is the simplest way to avoid cross-platform text bugs.

