1.3.3Python Intermediate

File I - O — open modes (r, w, a, rb), read, readline, readlines, write

2,104 words10 min readdifficulty · medium

WHY does file I/O even need "modes"?

Your program lives in RAM (fast, temporary). A file lives on disk (slow, permanent). To move data between them the OS needs to know your intent up front, because that intent decides:

  • WHAT — should the file already exist, or be created?
  • WHAT — should old contents be destroyed (truncated) or kept?
  • WHERE — should the cursor sit at the start or the end?
  • HOW — are we moving human-readable text (decoded with an encoding like UTF-8) or raw bytes?

A "mode" is a tiny code that answers all of these at once.


The mode table (memorise this 80/20 core)

Mode Reads? Writes? File must exist? Truncates? Cursor start Returns
r ✅ (else error) start str
w no (creates) wipes! start str
a no (creates) end str
rb start bytes
r+ start str
wb no start bytes
Figure — File I - O — open modes (r, w, a, rb), read, readline, readlines, write

HOW to read: three methods, one cursor

There is one cursor per file object. Every read advances it. That's the single fact that explains all the surprising behaviour below.

Worked example — reading the same file 3 ways

Suppose notes.txt contains:

apple
banana
cherry
with open("notes.txt", "r", encoding="utf-8") as f:
    whole = f.read()        # 'apple\nbanana\ncherry\n'

Why this step? read() slurps everything; cursor now at end-of-file (EOF). A second read() would return ''.

with open("notes.txt") as f:
    first = f.readline()    # 'apple\n'
    second = f.readline()   # 'banana\n'

Why this step? Each readline() stops at the \n and leaves the cursor right after it, so the next call continues where the last stopped — the cursor remembers.

with open("notes.txt") as f:
    lines = f.readlines()   # ['apple\n', 'banana\n', 'cherry\n']
    clean = [ln.rstrip("\n") for ln in lines]  # ['apple','banana','cherry']

Why this step? readlines() keeps the \n; we strip it with rstrip because we usually want the text, not the line break.


HOW to write: write and writelines

Worked example — write vs append

with open("log.txt", "w", encoding="utf-8") as f:   # WIPES log.txt
    f.write("start\n")
    f.write("step1\n")
# file now: 'start\nstep1\n'
 
with open("log.txt", "a", encoding="utf-8") as f:   # keep, cursor at END
    f.write("step2\n")
# file now: 'start\nstep1\nstep2\n'

Why this step? Opening with w the second time would have deleted start/step1. a preserves and adds — that's the whole difference between the two.


HOW binary differs

with open("pic.png", "rb") as f:
    header = f.read(8)      # b'\x89PNG\r\n\x1a\n'  -> a bytes object

Why this step? A PNG isn't text; decoding it as UTF-8 would crash. rb hands you raw bytes you can inspect (the first 8 bytes are PNG's magic number).


Common mistakes (Steel-man + fix)


Recall Feynman: explain it to a 12-year-old

A file is like a notebook on a shelf. open() is you walking up and saying what you want to do: r = "I'll only read it," w = "rip out all pages and write fresh," a = "flip to the last page and keep writing." Your finger is the cursor — every time you read a line, your finger slides down, so the next read starts from there. read() reads the whole notebook at once; readline() reads one line and stops; readlines() photocopies every line into a list. And with is a polite friend who closes the notebook for you when you're done.


Active recall

What does mode r require and do?
File must already exist; opens read-only with cursor at start; error if missing.
What does mode w do to existing contents?
Truncates the file to empty immediately on open (data lost), then writes from the start; creates the file if absent.
What does mode a do with the cursor?
Opens for writing with the cursor at the END; existing data is preserved, new data appended; creates file if absent.
What is different about rb vs r?
rb is binary: reads bytes (not str), performs no decoding and no newline translation.
What does f.read() return and where is the cursor after?
Entire remaining file as one string; cursor left at EOF (next read gives '').
What does f.readline() return?
One line up to and including the next \n; advances cursor past it.
What does f.readlines() return?
A list of all remaining lines as strings, each still containing its trailing \n.
Does f.write(s) add a newline?
No — it writes s verbatim and returns the count of characters written.
Why prefer for line in f: over f.readlines()?
It reads lazily, one line at a time, so it never loads the whole file into memory.
How do you re-read a file after reaching EOF without reopening?
Call f.seek(0) to move the cursor back to the start.
Why use with open(...) as f:?
It auto-closes and flushes the file even if an exception occurs, preventing lost writes and leaked handles.
What does the + in modes like r+ mean?
Open for both reading and writing.

Connections

  • Context Managers (with statement) — why with guarantees close().
  • Strings and Encoding (UTF-8) — what text mode decodes for you.
  • Bytes vs str — the type difference behind b mode.
  • Exceptions try-except — handling FileNotFoundError from r.
  • os and pathlib — building safe file paths.
  • Generators and Lazy Iteration — why for line in f: is memory-cheap.

Concept Map

returns

mode encodes

base letter

optional b

r

w

a

has one

advanced by

read

readline

readlines

write

open path mode encoding

file object

mode string

r w a x

binary bytes vs text str

reads existing file

truncates then writes

cursor at end appends

single cursor

read readline readlines

entire rest as one str

one line up to newline

list of all lines

push data into file

Hinglish (regional understanding)

Intuition Hinglish mein samjho

Dekho, file ek disk par padi hui notebook ki tarah hai, aur open() karte waqt tum bas batate ho ki tumhe usse kya karna hai. r matlab "sirf padhunga" — file pehle se honi chahiye. w matlab "saare purane page phaad do aur naya likho" — yahi sabse bada trap hai, kyunki file khulte hi data delete ho jaata hai. a (append) matlab "purana sab rakho, bas last page se aage likho". Aur b lagao to tum raw bytes ke saath kaam karte ho (image, audio jaise files), text decode nahi hota.

Sabse important concept hai cursor. Har file object ke andar ek ungli (pointer) hoti hai jo batati hai abhi kahan ho. Jab tum read() ya readline() karte ho, ye ungli aage khisak jaati hai. Isiliye read() doosri baar karoge to khaali '' milega — kyunki ungli already end (EOF) par pahunch chuki hai. Wapas shuru se padhna ho to f.seek(0) karo.

Reading ke teen tareeke: read() poori file ek string mein, readline() ek line, aur readlines() saari lines ka list (har line mein \n bhi aata hai, usse rstrip("\n") se hatao). Bade files ke liye for line in f: best hai — ye ek-ek line lazy tareeke se padhta hai, RAM nahi bharta. Writing mein yaad rakho: write() khud se newline NAHI lagata, tumhe \n daalna padega.

Last cheez — hamesha with open(...) as f: use karo. Ye apne aap file close aur flush kar deta hai, chahe beech mein error bhi aa jaye. Isse data safe rehta hai aur file handles leak nahi hote. Bas itna samajh lo to File I/O ka 80% kaam ho gaya.

Go deeper — visual, from zero

Test yourself — Python Intermediate

Connections