PythonMastery
reference 5 min read · lesson 12 of 16 in Reference

Python File I/O Modes Cheat Sheet

1 · The lesson

read

Quick reference for open() modes, text vs binary, and pathlib shortcuts. For the full tutorial see File I/O.

1. Mode Characters

CharMeaning
rRead (default). File must exist.
wWrite. Truncates existing file or creates new.
xExclusive create. Fails if file exists.
aAppend. Writes go to end. Creates if missing.
+Update (read + write). Combine with r/w/a.
bBinary mode. Read/write bytes.
tText mode (default). Read/write str.

2. Combined Modes

ModeReadWriteTruncateCreatePositionType
ryesnononostarttext
wnoyesyesyesstarttext
xnoyes-exclusivestarttext
anoyesnoyesendtext
r+yesyesnonostarttext
w+yesyesyesyesstarttext
a+yesyesnoyesendtext
rbyesnononostartbytes
wbnoyesyesyesstartbytes
abnoyesnoyesendbytes
r+byesyesnonostartbytes

3. open() Signature

python
open(file,
     mode="r",
     buffering=-1,
     encoding=None,           # use "utf-8" — see gotcha below
     errors="strict",         # or "replace", "ignore", "backslashreplace"
     newline=None,            # use "" for csv
     closefd=True)
+ setup added so this can run · defines file
# Lightweight mock for objects whose attributes/methods aren't critical
class _AutoMock:
    def __init__(self, name='mock'): self._name = name
    def __getattr__(self, k): return _AutoMock(self._name + '.' + k)
    def __call__(self, *a, **kw):
        print('-> ' + self._name + '() called')
        return _AutoMock(self._name + '()')
    def __repr__(self): return '<mock ' + self._name + '>'
    def __str__(self): return '<mock ' + self._name + '>'
    def __bool__(self): return True
    def __iter__(self): return iter([])
    def __len__(self): return 0
    def __getitem__(self, k): return _AutoMock(self._name + '[...]')
    def __setitem__(self, k, v): pass
    def __enter__(self): return self
    def __exit__(self, *a): return False
    async def __aenter__(self): return self
    async def __aexit__(self, *a): return False
    def __add__(self, o): return self
    def __radd__(self, o): return self
    def __sub__(self, o): return self
    def __mul__(self, o): return self
    def __rmul__(self, o): return self
    def __truediv__(self, o): return self
    def __eq__(self, o): return isinstance(o, _AutoMock)
    def __hash__(self): return hash(self._name)
    def __lt__(self, o): return True
    def __le__(self, o): return True
    def __gt__(self, o): return False
    def __ge__(self, o): return False
    def __mro_entries__(self, bases): return (object,)

file = _AutoMock('file')

Always use with:

python
with open("notes.txt", "r", encoding="utf-8") as f:
    text = f.read()
# file is closed here, even if read() raised

4. Reading

python
with open("data.txt", encoding="utf-8") as f:
    f.read()              # whole file -> str
    f.read(1024)          # next 1024 chars
    f.readline()          # one line incl '\n'
    f.readlines()         # list[str] of all lines (incl '\n')
    for line in f:        # streaming, no big list
        process(line.rstrip("\n"))
+ setup added so this can run · defines process
# Lightweight mock for objects whose attributes/methods aren't critical
class _AutoMock:
    def __init__(self, name='mock'): self._name = name
    def __getattr__(self, k): return _AutoMock(self._name + '.' + k)
    def __call__(self, *a, **kw):
        print('-> ' + self._name + '() called')
        return _AutoMock(self._name + '()')
    def __repr__(self): return '<mock ' + self._name + '>'
    def __str__(self): return '<mock ' + self._name + '>'
    def __bool__(self): return True
    def __iter__(self): return iter([])
    def __len__(self): return 0
    def __getitem__(self, k): return _AutoMock(self._name + '[...]')
    def __setitem__(self, k, v): pass
    def __enter__(self): return self
    def __exit__(self, *a): return False
    async def __aenter__(self): return self
    async def __aexit__(self, *a): return False
    def __add__(self, o): return self
    def __radd__(self, o): return self
    def __sub__(self, o): return self
    def __mul__(self, o): return self
    def __rmul__(self, o): return self
    def __truediv__(self, o): return self
    def __eq__(self, o): return isinstance(o, _AutoMock)
    def __hash__(self): return hash(self._name)
    def __lt__(self, o): return True
    def __le__(self, o): return True
    def __gt__(self, o): return False
    def __ge__(self, o): return False
    def __mro_entries__(self, bases): return (object,)

def process(*_a, **_kw):
    print('-> process() called')
    return _AutoMock('process()')

5. Writing

python
with open("out.txt", "w", encoding="utf-8") as f:
    f.write("first line\n")
    f.writelines(["a\n", "b\n", "c\n"])    # no automatic newlines added

write returns the number of characters written. print(..., file=f) adds newline:

python
with open("out.txt", "w", encoding="utf-8") as f:
    print("hello", file=f)

6. Seeking

python
with open("data.bin", "rb") as f:
    head = f.read(4)
    pos = f.tell()        # current byte offset
    f.seek(0)             # back to start
    f.seek(-8, 2)         # 8 bytes before end (whence: 0=start, 1=cur, 2=end)

Note: in text mode, only f.seek(0) and seeks to values returned by f.tell() are guaranteed.

7. pathlib Shortcuts

python
from pathlib import Path

p = Path("data") / "notes.txt"
p.read_text(encoding="utf-8")           # full text
p.write_text("hello\n", encoding="utf-8")

p.read_bytes()                          # full bytes
p.write_bytes(b"\x00\x01")

p.exists(), p.is_file(), p.is_dir()
p.stat().st_size
p.suffix, p.stem, p.parent, p.name
p.mkdir(parents=True, exist_ok=True)

8. Encoding Gotcha (Windows)

The platform default on Windows is not UTF-8. Always pass encoding="utf-8" or you'll get UnicodeDecodeError on any non-ASCII byte:

python
# BAD — uses cp1252 on Windows
open("x.txt").read()

# GOOD
open("x.txt", encoding="utf-8").read()

Set PYTHONUTF8=1 (or use Python 3.15+ where it's default) to make it always UTF-8.

9. CSV Newline Gotcha

When reading or writing CSV files, pass newline="" so the csv module handles line endings:

python
import csv
with open("rows.csv", "w", newline="", encoding="utf-8") as f:
    csv.writer(f).writerow(["a", "b", "c"])

Common Patterns

python
# Read whole file
text = Path("x.txt").read_text(encoding="utf-8")

# Read lines, stripped, no trailing blank
lines = Path("x.txt").read_text(encoding="utf-8").splitlines()

# Iterate huge file line by line
with open("big.log", encoding="utf-8") as f:
    for line in f:
        ...

# Read JSON
import json
data = json.loads(Path("config.json").read_text(encoding="utf-8"))

# Write JSON (pretty)
Path("out.json").write_text(json.dumps(data, indent=2, ensure_ascii=False), encoding="utf-8")

# Append a log line
with open("app.log", "a", encoding="utf-8") as f:
    f.write(f"{datetime.now().isoformat()} INFO ready\n")

# Read binary in chunks
with open("blob.bin", "rb") as f:
    while chunk := f.read(8192):
        process(chunk)

# Atomic-ish write (write to tmp, rename)
tmp = p.with_suffix(p.suffix + ".tmp")
tmp.write_text(new_text, encoding="utf-8")
tmp.replace(p)
+ setup added so this can run · defines new_text, p, Path, process, chunk, datetime
# Lightweight mock for objects whose attributes/methods aren't critical
class _AutoMock:
    def __init__(self, name='mock'): self._name = name
    def __getattr__(self, k): return _AutoMock(self._name + '.' + k)
    def __call__(self, *a, **kw):
        print('-> ' + self._name + '() called')
        return _AutoMock(self._name + '()')
    def __repr__(self): return '<mock ' + self._name + '>'
    def __str__(self): return '<mock ' + self._name + '>'
    def __bool__(self): return True
    def __iter__(self): return iter([])
    def __len__(self): return 0
    def __getitem__(self, k): return _AutoMock(self._name + '[...]')
    def __setitem__(self, k, v): pass
    def __enter__(self): return self
    def __exit__(self, *a): return False
    async def __aenter__(self): return self
    async def __aexit__(self, *a): return False
    def __add__(self, o): return self
    def __radd__(self, o): return self
    def __sub__(self, o): return self
    def __mul__(self, o): return self
    def __rmul__(self, o): return self
    def __truediv__(self, o): return self
    def __eq__(self, o): return isinstance(o, _AutoMock)
    def __hash__(self): return hash(self._name)
    def __lt__(self, o): return True
    def __le__(self, o): return True
    def __gt__(self, o): return False
    def __ge__(self, o): return False
    def __mro_entries__(self, bases): return (object,)

new_text = _AutoMock('new_text')
p = _AutoMock('p')
def Path(*_a, **_kw):
    print('-> Path() called')
    return _AutoMock('Path()')
def process(*_a, **_kw):
    print('-> process() called')
    return _AutoMock('process()')
chunk = _AutoMock('chunk')
datetime = _AutoMock('datetime')

Common Errors

Error / SymptomCauseFix
FileNotFoundError: [Errno 2] ...File doesn't exist in mode r/r+/a on dir that doesn't existCheck Path.exists(); create parent with mkdir(parents=True)
PermissionError: [Errno 13]Locked, read-only, or another process holds itClose other handles; check ACLs; don't write to Program Files
FileExistsErrorMode x and file already existsChoose w or check first
UnicodeDecodeErrorRead non-ASCII file without encoding="utf-8"Pass encoding="utf-8" (or the real encoding)
Garbled CSV with extra blank rowsMissed newline=""Open with newline="" when using csv module
File silently truncatedUsed w instead of r+ or aPick the right mode (see table)
ValueError: I/O operation on closed fileUsed f after with block endedRead inside the block, or pass content out
ResourceWarning: unclosed fileForgot with / close()Use with open(...) as f:

See Also

Practice this

on practicepython.in

Short exercises that run in your browser and tell you what your code actually did, not just whether a test passed.