Reading and writing files is one of the first truly useful things you do in Python: saving results, loading configuration, processing logs, exporting data. Python's file handling is simple but has a few rules — modes, encodings, and proper closing — that separate fragile scripts from robust ones.
This guide covers file handling end-to-end: opening files with the right mode, reading whole files or line-by-line, writing and appending, the essential with statement, handling paths safely with pathlib, and working with CSV and JSON. Every example is runnable with its output.
Opening a File: open() and Modes
The built-in open(path, mode) returns a file object. The mode decides what you can do.
| Mode | Meaning |
|---|---|
'r' | Read (default); error if file is missing |
'w' | Write; creates or truncates the file |
'a' | Append; adds to the end, keeps existing content |
'x' | Create; error if the file already exists |
'b' / 't' | Binary / text (default), e.g. 'rb' |
'r+' | Read and write |
Why You Should Always Use with
A file must be closed to flush data and free the OS handle. The with statement (a context manager) closes it automatically — even if an error occurs. Always prefer it over manual open()/close().
# The recommended pattern
with open("notes.txt", "w", encoding="utf-8") as f:
f.write("Hello, file!\n")
f.write("Second line.\n")
# file is automatically closed here
print("done")
Output:
done
Reading Files
There are several ways to read, depending on whether you want the whole file or one line at a time.
with open("notes.txt", encoding="utf-8") as f:
content = f.read() # entire file as one string
print(content)
with open("notes.txt", encoding="utf-8") as f:
lines = f.readlines() # list of lines (keeps \n)
print(lines)
Output:
Hello, file!
Second line.
['Hello, file!\n', 'Second line.\n']
Reading line by line (memory-friendly)
Iterating the file object reads one line at a time — the right choice for large files.
with open("notes.txt", encoding="utf-8") as f:
for line in f:
print(line.strip()) # strip removes the trailing newline
Output:
Hello, file!
Second line.
Writing and Appending
'w' overwrites the whole file; 'a' adds to the end. Use writelines() to write a list of strings.
# Overwrite
with open("log.txt", "w", encoding="utf-8") as f:
f.writelines(["line 1\n", "line 2\n"])
# Append
with open("log.txt", "a", encoding="utf-8") as f:
f.write("line 3 (appended)\n")
with open("log.txt", encoding="utf-8") as f:
print(f.read())
Output:
line 1
line 2
line 3 (appended)
Working with Paths Using pathlib
The modern pathlib module handles file paths cleanly across operating systems and offers handy shortcuts.
from pathlib import Path
p = Path("data") / "report.txt" # OS-correct path joining
p.parent.mkdir(parents=True, exist_ok=True)
p.write_text("quick save\n", encoding="utf-8") # one-liner write
print(p.read_text(encoding="utf-8")) # one-liner read
print("exists?", p.exists(), "| name:", p.name)
Output:
quick save
exists? True | name: report.txt
Real-World Example: CSV and JSON
Two of the most common file formats. Use the standard csv and json modules — never parse them by hand.
import csv, json
# Write and read CSV
with open("people.csv", "w", newline="", encoding="utf-8") as f:
writer = csv.writer(f)
writer.writerow(["name", "age"])
writer.writerow(["Tushar", 25])
with open("people.csv", newline="", encoding="utf-8") as f:
for row in csv.reader(f):
print(row)
# Write and read JSON
data = {"name": "Tushar", "skills": ["python", "django"]}
with open("config.json", "w", encoding="utf-8") as f:
json.dump(data, f, indent=2)
with open("config.json", encoding="utf-8") as f:
print(json.load(f))
Output:
['name', 'age']
['Tushar', '25']
{'name': 'Tushar', 'skills': ['python', 'django']}
Common Mistakes to Avoid
- Forgetting to close files — use
withso it is automatic. - Opening with
'w'when you meant'a'—'w'silently erases the file. - Ignoring encoding — always pass
encoding="utf-8"for predictable text across platforms. - Reading a huge file with
read()— iterate line by line instead. - Hard-coding path separators like
"data/\\file"— usepathliboros.path.join. - Not handling
FileNotFoundErrorwhen a file may be missing.
Summary Table
| Task | Code |
|---|---|
| Read all | f.read() |
| Read lines (lazy) | for line in f: |
| Write (overwrite) | open(p, 'w') |
| Append | open(p, 'a') |
| Safe handling | with open(...) as f: |
| Quick read/write | Path(p).read_text() / write_text() |
Conclusion
File handling comes down to three habits: pick the correct mode, always use with, and specify the encoding. Add pathlib for clean cross-platform paths and the csv/json modules for structured data, and you can read, transform, and write almost any file safely.
Practice by writing a script that reads a text file, counts the words, and writes the result to a new file — using only with blocks.
π¬ Comments (0)
No comments yet. Be the first to share your thoughts!