Advanced File Handling in Python
This lesson continues from File Handling Basics and covers the file features used in real projects: more modes, moving the file cursor, encodings, binary files, CSV and JSON, folders, copying files, pathlib and writing your own context manager.
Setup
import os
import csv
import json
import shutil
from pathlib import Path
folder = "practice_files"
os.makedirs(folder, exist_ok=True) # create folder, no error if it exists
1. More modes
print("1. More file modes")
# "x" -> create a new file, error if it already exists
try:
with open(f"{folder}/new.txt", "x") as file:
file.write("Created with x mode\n")
print("new.txt created")
except FileExistsError:
print("new.txt already exists, x mode does not overwrite")
# "w+" -> write and read (erases old content)
with open(f"{folder}/notes.txt", "w+") as file:
file.write("Line 1\nLine 2\n")
file.seek(0) # go back to start before reading
print("w+ read:", file.read().split())
# "r+" -> read and write, file must exist, does NOT erase content
with open(f"{folder}/notes.txt", "r+") as file:
print("r+ read:", file.read().split())
file.write("Line 3\n") # cursor is at the end, so it adds here
# "a+" -> append and read
with open(f"{folder}/notes.txt", "a+") as file:
file.write("Line 4\n")
file.seek(0)
print("a+ read:", file.read().split())
2. seek() and tell()
print("\n2. seek() and tell()")
with open(f"{folder}/notes.txt", "r") as file:
print("Cursor at start:", file.tell())
file.read(6) # read 6 characters
print("After reading 6 chars:", file.tell())
file.seek(0) # move cursor back to start
print("After seek(0):", file.tell())
3. Encoding
Use encoding="utf-8" for Hindi, emojis or other special characters.
print("\n3. Encoding")
message = "नमस्ते Python"
with open(f"{folder}/hindi.txt", "w", encoding="utf-8") as file:
file.write(message)
with open(f"{folder}/hindi.txt", "r", encoding="utf-8") as file:
text = file.read()
# We compare instead of print, because some Windows terminals can't show Hindi
print("Hindi text saved and read back correctly:", text == message)
4. Binary files
"b" mode reads/writes bytes - used for images, PDFs, videos etc.
print("\n4. Binary files")
with open(f"{folder}/data.bin", "wb") as file:
file.write(bytes([65, 66, 67, 68])) # bytes of A B C D
with open(f"{folder}/data.bin", "rb") as source:
with open(f"{folder}/data_copy.bin", "wb") as target:
target.write(source.read()) # copy byte by byte
with open(f"{folder}/data_copy.bin", "rb") as file:
print("Copied bytes:", file.read())
5. Read a big file in chunks
For very big files, don't use read() - read small parts instead.
print("\n5. Reading in chunks of 10 characters")
with open(f"{folder}/notes.txt", "r") as file:
while True:
chunk = file.read(10)
if not chunk: # empty string means end of file
break
print(repr(chunk))
6. CSV files
print("\n6. CSV files")
students = [
["Name", "Age", "City"],
["Sudheer", 25, "Pune"],
["Divyani", 22, "Mumbai"],
]
# newline="" avoids blank lines between rows on Windows
with open(f"{folder}/students.csv", "w", newline="") as file:
writer = csv.writer(file)
writer.writerows(students)
with open(f"{folder}/students.csv", "r") as file:
reader = csv.DictReader(file) # each row becomes a dictionary
for row in reader:
print(row["Name"], "is", row["Age"], "years old from", row["City"])
7. JSON files
print("\n7. JSON files")
employee = {
"id": 101,
"name": "Sudheer",
"skills": ["Python", "SQL", "FastAPI"],
"active": True,
}
with open(f"{folder}/employee.json", "w") as file:
json.dump(employee, file, indent=4) # dict -> JSON file
with open(f"{folder}/employee.json", "r") as file:
data = json.load(file) # JSON file -> dict
print("Name :", data["name"])
print("Skills:", ", ".join(data["skills"]))
8. Folders with os
print("\n8. Folder operations")
print("Files in folder:", os.listdir(folder))
print("Size of notes.txt:", os.path.getsize(f"{folder}/notes.txt"), "bytes")
print("Is notes.txt a file?", os.path.isfile(f"{folder}/notes.txt"))
print("Is folder a folder? ", os.path.isdir(folder))
9. Copy and move with shutil
print("\n9. shutil copy and move")
os.makedirs(f"{folder}/backup", exist_ok=True)
shutil.copy(f"{folder}/students.csv", f"{folder}/backup/students.csv")
shutil.move(f"{folder}/data_copy.bin", f"{folder}/backup/data_copy.bin")
print("Backup folder:", os.listdir(f"{folder}/backup"))
10. pathlib
print("\n10. pathlib")
path = Path(folder) / "pathlib_demo.txt" # "/" joins paths
path.write_text("Written using pathlib\n") # open + write + close in one line
print("Content :", path.read_text().strip())
print("Name :", path.name)
print("Suffix :", path.suffix)
print("Exists :", path.exists())
print("All .txt files:", [p.name for p in Path(folder).glob("*.txt")])
11. Custom context manager
A class with __enter__ and __exit__ can be used with "with".
print("\n11. Custom context manager")
class MyFile:
def __init__(self, name, mode):
self.name = name
self.mode = mode
def __enter__(self):
print("Opening", self.name)
self.file = open(self.name, self.mode)
return self.file
def __exit__(self, exc_type, exc_value, traceback):
self.file.close()
print("Closed", self.name)
with MyFile(f"{folder}/custom.txt", "w") as file:
file.write("Written using my own context manager\n")