The built-in open() function opens a file and returns a file object. The mode determines the operation:
f = open("file.txt", "r") # read (default)
f = open("file.txt", "w") # write (overwrites!)
f = open("file.txt", "a") # append
f = open("file.txt", "x") # exclusive create (fails if exists)
f = open("file.txt", "rb") # read binary
f = open("file.txt", "wb") # write binary
# Read entire file as a string
with open("example.txt", "r") as f:
content = f.read()
# Read one line at a time
with open("example.txt", "r") as f:
line = f.readline()
while line:
print(line.strip())
line = f.readline()
# Read all lines into a list
with open("example.txt", "r") as f:
lines = f.readlines() # includes \n characters
# Iterate directly (memory-efficient)
with open("example.txt", "r") as f:
for line in f:
print(line.strip())
# write() writes a single string
with open("output.txt", "w") as f:
f.write("Hello, World!\n")
f.write("Second line\n")
# writelines() writes an iterable of strings
lines = ["Line 1\n", "Line 2\n", "Line 3\n"]
with open("output.txt", "w") as f:
f.writelines(lines)
"w" mode carefully — it overwrites the file without warning. For safety, check if the file exists first with os.path.exists() or use "x" mode.
The with statement automatically closes the file, even if an exception occurs:
# Bad: manual close
f = open("file.txt", "r")
data = f.read()
f.close()
# Good: automatic close
with open("file.txt", "r") as f:
data = f.read()
# File is closed automatically
with open("example.txt", "r") as f:
f.read(10) # read first 10 chars
pos = f.tell() # current position (10)
f.seek(0) # go back to beginning
f.seek(5) # go to byte 5
f.seek(0, 2) # seek to end (2 = whence end)
import os
os.rename("old.txt", "new.txt") # rename file
os.remove("file.txt") # delete file
os.mkdir("newdir") # create directory
os.rmdir("emptydir") # remove empty directory
os.listdir(".") # list directory contents
os.path.exists("file.txt") # check existence
os.path.isfile("file.txt") # is it a file?
os.path.isdir("mydir") # is it a directory?
os.path.join("dir", "file.txt") # platform-aware path join
pathlib provides an object-oriented approach to filesystem paths:
from pathlib import Path
p = Path("data/subdir")
p.mkdir(parents=True, exist_ok=True) # create dirs recursively
file = p / "notes.txt" # path join with /
file.write_text("Hello, Path!") # write text
content = file.read_text() # read text
file.exists() # True
file.is_file() # True
file.suffix # '.txt'
file.stem # 'notes'
file.name # 'notes.txt'
# Glob pattern matching
txt_files = Path(".").glob("*.txt")
py_files = Path("src").rglob("*.py") # recursive
# Delete file
file.unlink()
from pathlib import Path
# Create a log file and append entries
log = Path("app.log")
entries = [
"[INFO] Starting application",
"[INFO] Connected to database",
"[WARN] Memory usage above 80%",
"[ERROR] Connection timeout",
]
with log.open("a") as f:
for entry in entries:
f.write(entry + "\n")
# Read and filter errors
errors = [line for line in log.read_text().splitlines()
if "ERROR" in line]
print(f"Found {len(errors)} errors:")
for err in errors:
print(f" {err}")
# Backup the log
backup = log.parent / "backups" / f"app_{Path('log').stem}.bak"
backup.parent.mkdir(exist_ok=True)
backup.write_text(log.read_text())
# Clean up old backup files
for old in backup.parent.glob("*.bak"):
if old.stat().st_mtime < (time.time() - 86400 * 7):
old.unlink()
with statements for file operations. They guarantee proper resource cleanup. For new projects, pathlib is the recommended approach over os.path for path manipulation.
Write a program that: (1) creates a directory called notes if it doesn't exist, (2) creates 5 text files in it, each containing a numbered note, (3) reads all the files and concatenates their content into a single summary.txt, (4) prints the file names and sizes of all .txt files in the directory, and (5) then deletes the note files (keeping the directory). Use pathlib for all path operations.