Reading Files with UTF-8 Encoding
Use io.open with mode='wt' and encoding='utf-8' to write Unicode text to files.
From Text to Stored Bytes
A Python string can contain characters such as é, €, 中, and こんにちは. A file system stores file data as bytes, so Python must translate the Unicode characters in the string into bytes before storing them. This translation is called encoding. UTF-8 performs that translation automatically when you open the file with encoding='utf-8'.
The important boundary is between Unicode text in Python and bytes in the file. With UTF-8 selected, Python handles the conversion instead of requiring you to convert each character manually.
The UTF-8 Conversion Step
When f.write() is called on a file opened with encoding='utf-8', Python converts each Unicode character into one or more bytes according to the UTF-8 encoding scheme. Characters do not all require the same number of bytes. For example, the Euro sign € has Unicode code point U+20AC and is represented in UTF-8 by the three bytes 0xE2, 0x82, and 0xAC. Those bytes are stored sequentially in the file.
Encoding the Euro Sign
What happens when a UTF-8 text file receives the character €?
Start with Unicode text: The Python string contains the Unicode character €.
Select UTF-8: The file was opened with encoding='utf-8', so Python uses UTF-8 for the text-to-byte conversion.
Convert the character: The character € is represented in UTF-8 as the three bytes 0xE2, 0x82, and 0xAC.
Store the bytes: The three bytes are written sequentially to the file.
The Unicode character is preserved in the file as its UTF-8 byte sequence.
Opening a Text File
import io with io.open("messages.txt", mode="wt", encoding="utf-8") as f: f.write("Français\n") f.write("こんにちは\n") f.write("€")
The file contains:
Français
こんにちは
€Encoding Parameter Control
The encoding='utf-8' argument tells io.open how Unicode text should be translated before it is written. Without an explicitly selected encoding, the behavior may not be consistent across systems. Specifying UTF-8 makes the intended conversion clear and helps preserve non-ASCII characters so that other programs can read them correctly when they understand UTF-8.
Unicode String Literals
In Python 3, strings are Unicode by default. A u prefix, as in u"Français", is optional but can clarify that the value is intended as Unicode text. The prefix was more significant in Python 2, where regular strings were byte strings by default. In Python 3, these two forms express the same Unicode-string intent.
| String form | Meaning in Python 3 | Use |
|---|---|---|
| "Français" | A Unicode string | Normal Python 3 spelling |
| u"Français" | A Unicode string | Optional clarity and compatibility notation |
Safe File Cleanup
A file should be closed after writing. You can close it explicitly, but a with statement is the safer and cleaner approach. The context manager automatically closes the file when the block ends, including when an error occurs during writing.
Use the with form as the default pattern for writing text files. It keeps the opening, writing, and cleanup steps together and guarantees cleanup through the context manager.
When Encodings Disagree
Encoding problems become easier to investigate when you trace the complete path: Unicode text in the Python string, the encoding selected when the file is written, the bytes stored in the file, and the encoding understood by the program or editor that reads it. If the intended UTF-8 encoding is not used consistently, non-ASCII characters may not appear correctly in the output.
Opening a text file without explicitly specifying UTF-8
The intended text encoding is not stated explicitly, so behavior may not be consistent across systems.
Fix:
Use io.open with mode='wt' and encoding='utf-8'.Manually converting every character to bytes before writing
A text file opened with encoding='utf-8' performs the Unicode-to-byte conversion automatically.
Fix:
Write Unicode strings directly to the UTF-8 text file.Forgetting to close the file
File cleanup is not completed reliably.
Fix:
Use a with statement so the file closes automatically, even if an error occurs during writing.Assuming the u prefix is required in Python 3
Python 3 strings are Unicode by default.
Fix:
Use the u prefix only when it improves clarity or compatibility.
Practice the Trace
Write a short Python program that opens notes.txt with io.open in text-writing mode and UTF-8 encoding. Write one line containing € and one line containing 中. Use a with statement. Then identify which step performs the conversion from Unicode characters to bytes.
Hints
- Import io before calling io.open.
- Use mode='wt' and encoding='utf-8'.
- Place the write calls inside the with block.
- The conversion occurs when text is written through the UTF-8-configured file object.
What do you think happens?
What happens to the characters in this statement when it runs: f.write("Français") on a file opened with encoding='utf-8'?
Reveal answer
Answer: Python converts the Unicode characters into UTF-8 bytes automatically.
The UTF-8 encoding selected when the file was opened controls the automatic conversion performed during f.write().
Key Takeaways
- Use io.open with mode='wt' and encoding='utf-8' to write Unicode text to a file.
- UTF-8 converts each Unicode character into one or more bytes, which are stored sequentially.
- The encoding parameter selects the text-to-byte conversion used during f.write().
- Python 3 strings are Unicode by default, so the u prefix is optional.
- Use a with statement to close the file automatically and consistently.
Key Takeaways
- Open text files with io.open, mode='wt', and encoding='utf-8'.
- Python automatically encodes Unicode strings as UTF-8 bytes during writing.
- A single Unicode character can become multiple UTF-8 bytes, such as € becoming 0xE2, 0x82, and 0xAC.
- Specify UTF-8 explicitly and use a with statement for predictable encoding and safe cleanup.
- When characters display incorrectly, trace the text, writing encoding, stored bytes, and reading encoding for consistency.