C.W.K.
Stream
Lesson 01 of 06 · published

open() — Modes, Encoding, and the File Object

~20 min · open, file, mode, encoding

Level 0Curious
0 XP0/93 lessons0/23 achievements
0/100 XP to next level100 XP to go0% complete

open() — the workhorse

open(path, mode='r', encoding=None) returns a file object you read from or write to. The two arguments that matter most are mode and encoding. Mode tells Python whether you're reading or writing, and whether the file is text or binary. Encoding tells Python how to convert bytes to/from text — UTF-8 is the modern default and you should rarely need anything else.

Mode strings — five letters that combine

r read (default), w write (truncate first), a append, x create-only (fails if exists), + read-and-write, b binary, t text (default). Combinations: rb read binary, w+ write+read, a+b append+read+binary. The text/binary distinction matters: text mode does encoding/decoding and newline translation; binary mode is raw bytes.

Always use the with-statement

with open(path) as f: guarantees the file is closed even if an exception is raised inside the block. The alternative — f = open(path); ... f.close() — is correct only if no exception fires between open and close, and that's a constraint you cannot promise. Use with. Period.

The encoding argument — UTF-8 by default isn't actually true

Surprise: open() uses the system's default encoding when you don't specify one, which on Windows is often cp1252 or similar. This bites cross-platform code. The fix: open(path, encoding='utf-8'), always, when you're reading or writing text. Python 3.11+ added encoding="locale" to make the locale-derived behavior explicit.

Warning: Mixing text and binary modes in the same file at different times is a recipe for bugs. Pick one and stick with it. If you need both, manage two file objects or seek-and-reopen explicitly. Don't try to use r+b as a way to switch.

Code

open() — read text and write text·python
# Read whole file
with open("/etc/hostname", encoding="utf-8") as f:
    content = f.read()
print(content.strip())

# Write — overwrite
with open("/tmp/out.txt", "w", encoding="utf-8") as f:
    f.write("hello\n")
    f.write("world\n")

# Append
with open("/tmp/out.txt", "a", encoding="utf-8") as f:
    f.write("more\n")

# Create-only — fails if it exists
try:
    with open("/tmp/out.txt", "x", encoding="utf-8") as f:
        f.write("won't get here")
except FileExistsError as e:
    print("already exists:", e)
Reading line-by-line — the streaming idiom·python
# Don't do this for large files
# data = open("big.log", encoding="utf-8").read()      # loads everything

# Do this — file objects are iterable line-by-line
with open("/tmp/out.txt", encoding="utf-8") as f:
    for line in f:
        print("got:", line.rstrip("\n"))

# .readlines() — list of lines, eager
with open("/tmp/out.txt", encoding="utf-8") as f:
    lines = f.readlines()
    print(lines)              # ['hello\n', 'world\n', 'more\n']
Binary mode — bytes in, bytes out·python
# Reading a binary file
with open("/bin/ls", "rb") as f:
    header = f.read(4)
print(header)                  # b'\x7fELF' on Linux/macOS

# Writing bytes
with open("/tmp/raw.bin", "wb") as f:
    f.write(b"\xDE\xAD\xBE\xEF")

# Don't forget — text and binary are different file modes
try:
    with open("/tmp/raw.bin", "r") as f:    # text mode!
        f.read()                              # may raise UnicodeDecodeError
except UnicodeDecodeError as e:
    print("as expected:", e)
Seek and tell — repositioning·python
# Open with read+write to seek inside the file
with open("/tmp/seek.txt", "w+", encoding="utf-8") as f:
    f.write("hello world")
    print("position:", f.tell())          # 11
    f.seek(0)
    print(f.read(5))                      # 'hello'
    f.seek(6)
    print(f.read())                       # 'world'

# Binary mode is required for byte-precise seeking on multi-byte content
Always specify encoding for text files·python
# This works on Linux but might break on Windows when the system locale
# doesn't produce UTF-8
# with open("data.txt") as f:
#     contents = f.read()

# Always specify encoding
with open("/tmp/out.txt", encoding="utf-8") as f:
    contents = f.read()
print(contents[:50])

# 3.11+ adds "locale" for explicit "use the locale" — different from default
# with open("data.txt", encoding="locale") as f: ...

External links

Exercise

Write three programs: (a) Create a file /tmp/quest_test.txt, write three lines to it (using open with with). (b) Open the same file for reading and print each line with its line number. (c) Append a fourth line, then re-read the file and verify all four lines are present. Always specify encoding='utf-8'. Use with blocks.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.