Working with Files
Reading from and writing to files in Python
Introduction
Working with files is essential for many programming tasks. Whether you're reading configuration files, processing data, saving user input, or logging information, Python provides simple and powerful tools for file operations. This lesson covers reading from files, writing to files, and best practices for safe file handling.
Opening Files
Before you can read or write to a file, you need to open it. Python's open() function is used for this purpose.
Basic File Opening
# Open a file for reading
file = open("data.txt", "r")
content = file.read()
file.close() # Always close files!
# Open a file for writing
file = open("output.txt", "w")
file.write("Hello, World!")
file.close()
# File modes:
# "r" - Read (default)
# "w" - Write (overwrites existing file)
# "a" - Append (adds to end of file)
# "x" - Exclusive creation (fails if file exists)
# "b" - Binary mode (e.g., "rb", "wb")
# "t" - Text mode (default, e.g., "rt", "wt")
# "+" - Read and write (e.g., "r+", "w+")The with Statement (Recommended)
The with statement automatically closes files, even if an error occurs. This is the recommended way to work with files:
# Using 'with' statement (recommended)
with open("data.txt", "r") as file:
content = file.read()
# File is automatically closed when block exits
# Even if an error occurs!
# Equivalent to:
file = open("data.txt", "r")
try:
content = file.read()
finally:
file.close() # Always executedBest Practice: Always use the with statement when working with files. It ensures files are properly closed and prevents resource leaks.
Reading Files
Python provides several methods for reading file content, each useful for different scenarios.
Reading Entire File
# Read entire file as string
with open("data.txt", "r") as file:
content = file.read()
print(content)
# Read entire file as list of lines
with open("data.txt", "r") as file:
lines = file.readlines()
for line in lines:
print(line.strip()) # strip() removes newline charactersReading Line by Line
For large files, reading line by line is memory-efficient:
# Method 1: Iterate directly over file object
with open("data.txt", "r") as file:
for line in file:
print(line.strip()) # Process each line
# Method 2: Using readline() in a loop
with open("data.txt", "r") as file:
line = file.readline()
while line:
print(line.strip())
line = file.readline()
# Method 3: Read specific number of characters
with open("data.txt", "r") as file:
chunk = file.read(100) # Read first 100 characters
print(chunk)Reading with Error Handling
def read_file_safely(filename):
"""Read file content with proper error handling."""
try:
with open(filename, "r") as file:
content = file.read()
return content
except FileNotFoundError:
print(f"Error: File '{filename}' not found.")
return None
except PermissionError:
print(f"Error: Permission denied to read '{filename}'.")
return None
except Exception as e:
print(f"Unexpected error: {e}")
return None
# Usage
content = read_file_safely("data.txt")
if content:
print("File read successfully!")
print(content)Writing Files
Writing to files allows you to save data, create logs, and generate output files.
Writing Text
# Write mode ("w") - overwrites existing file
with open("output.txt", "w") as file:
file.write("Hello, World!\n")
file.write("This is line 2\n")
file.write("This is line 3")
# Append mode ("a") - adds to end of file
with open("output.txt", "a") as file:
file.write("\nThis line is appended")
# Writing multiple lines
lines = ["Line 1\n", "Line 2\n", "Line 3\n"]
with open("output.txt", "w") as file:
file.writelines(lines)
# Or use write() with join
with open("output.txt", "w") as file:
file.write("\n".join(["Line 1", "Line 2", "Line 3"]))Write vs Append
Write Mode ("w")
- Overwrites existing file
- Creates new file if it doesn't exist
- Use for creating new files
- Deletes existing content
Append Mode ("a")
- Adds to end of existing file
- Creates new file if it doesn't exist
- Use for logs or accumulating data
- Preserves existing content
Writing with Error Handling
def write_file_safely(filename, content):
"""Write content to file with error handling."""
try:
with open(filename, "w") as file:
file.write(content)
print(f"Successfully wrote to {filename}")
return True
except PermissionError:
print(f"Error: Permission denied to write to '{filename}'.")
return False
except Exception as e:
print(f"Unexpected error: {e}")
return False
# Usage
success = write_file_safely("output.txt", "Hello, World!")
if success:
print("File written successfully!")Working with File Paths
Understanding file paths is important for working with files in different locations.
Relative vs Absolute Paths
# Relative path (relative to current working directory)
with open("data.txt", "r") as file:
content = file.read()
# Relative path with subdirectory
with open("data/input.txt", "r") as file:
content = file.read()
# Absolute path (full path from root)
with open("/home/user/documents/data.txt", "r") as file:
content = file.read()
# On Windows
with open("C:\\Users\\User\\Documents\\data.txt", "r") as file:
content = file.read()Using os.path (Cross-Platform)
The os.path module helps create cross-platform paths:
import os
# Join path components (handles / or \ automatically)
file_path = os.path.join("data", "input", "file.txt")
# On Linux/Mac: "data/input/file.txt"
# On Windows: "data\input\file.txt"
with open(file_path, "r") as file:
content = file.read()
# Get current working directory
current_dir = os.getcwd()
print(f"Current directory: {current_dir}")
# Check if file exists
if os.path.exists("data.txt"):
print("File exists!")
else:
print("File does not exist!")
# Get absolute path
abs_path = os.path.abspath("data.txt")
print(f"Absolute path: {abs_path}")Using pathlib (Modern Approach)
The pathlib module (Python 3.4+) provides an object-oriented approach:
from pathlib import Path
# Create path object
file_path = Path("data") / "input" / "file.txt"
# Works on all platforms!
# Read file
with open(file_path, "r") as file:
content = file.read()
# Or use pathlib's read_text method
content = file_path.read_text()
# Write file
file_path.write_text("Hello, World!")
# Check if exists
if file_path.exists():
print("File exists!")
# Get parent directory
parent = file_path.parent
print(f"Parent: {parent}")
# Get filename
filename = file_path.name
print(f"Filename: {filename}")Common File Operations
Processing CSV-like Data
# Reading and processing a simple CSV file
with open("data.csv", "r") as file:
for line in file:
# Split by comma (simple CSV parsing)
fields = line.strip().split(",")
if len(fields) >= 2:
name = fields[0]
age = fields[1]
print(f"Name: {name}, Age: {age}")
# Writing CSV-like data
data = [
["Alice", "30", "Engineer"],
["Bob", "25", "Designer"],
["Charlie", "35", "Manager"]
]
with open("output.csv", "w") as file:
for row in data:
file.write(",".join(row) + "\n")Reading Configuration Files
# Simple key=value configuration file
config = {}
with open("config.txt", "r") as file:
for line in file:
line = line.strip()
if line and not line.startswith("#"): # Skip empty lines and comments
key, value = line.split("=", 1)
config[key.strip()] = value.strip()
print(config)
# Example config.txt:
# host=localhost
# port=8080
# debug=TrueLogging to Files
import datetime
def log_message(message, log_file="app.log"):
"""Append timestamped message to log file."""
timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
log_entry = f"[{timestamp}] {message}\n"
with open(log_file, "a") as file:
file.write(log_entry)
# Usage
log_message("Application started")
log_message("Processing data...")
log_message("Application finished")
# Log file contains:
# [2024-01-15 10:30:00] Application started
# [2024-01-15 10:30:05] Processing data...
# [2024-01-15 10:30:10] Application finishedBinary Files
For binary files (images, executables, etc.), use binary mode:
# Reading binary file
with open("image.jpg", "rb") as file:
binary_data = file.read()
# Process binary data...
# Writing binary file
with open("copy.jpg", "wb") as file:
file.write(binary_data)
# Copying a file (binary mode)
def copy_file(source, destination):
with open(source, "rb") as src:
with open(destination, "wb") as dst:
dst.write(src.read())
copy_file("original.jpg", "copy.jpg")Best Practices
✓ Do
- Always use
withstatement - Handle file errors with try/except
- Use appropriate file modes
- Check if file exists before reading
- Use
pathlibfor modern code - Close files explicitly if not using
with
✗ Don't
- Forget to close files
- Ignore file errors
- Use hardcoded paths
- Read entire large files into memory
- Write without error handling
- Assume file exists
Key Takeaways
Opening Files
- Use
open()function - Always use
withstatement - Choose appropriate mode (r, w, a)
- Files auto-close with
with
Reading Files
read()- entire filereadline()- one linereadlines()- all lines- Iterate for large files
Writing Files
write()- write stringwritelines()- write list- "w" mode overwrites
- "a" mode appends
File Paths
- Use
os.pathfor compatibility - Use
pathlibfor modern code - Handle relative/absolute paths
- Check file existence
What's Next?
Great work! You now know how to read from and write to files. This is a fundamental skill for many real-world applications. In future lessons, we'll explore:
- Modules and packages - Organize and reuse your Python code effectively
- String manipulation - Master string operations, slicing, and modern formatting
- List comprehensions - Write cleaner, more Pythonic code with elegant one-liners
- Standard library essentials - Leverage powerful built-in tools like datetime, json, and collections