Files and Exceptions in
Python: Essential Concepts
and Examples
A practical guide to working with files and handling errors in Python programming
What Is File Handling in Python?
File handling is a fundamental skill for any Python developer, enabling you
to:
• Process data from external sources
• Store information persistently between program executions
• Generate reports and log program activity
• Work with configuration files
File Operations: The Basics
Opening Files Reading Files
file = open("data.txt", "r") content = file.read()
The open() function takes a filename and mode parameter Read entire file content as a single string
Writing Files Closing Files
file.write("Hello Python") file.close()
Write string data to the file Always close files to prevent resource leaks
The Context Manager (`with`
Statement)
The Problem with Manual The Solution: Context
Closing Manager
file = open("data.txt", "r")# If an with open("data.txt", "r") as file:
error occurs here, file may never content = file.read()# File
closecontent = automatically closes when
file.read()file.close() # May leaving the block
never execute
The with statement ensures files are
properly closed even if exceptions
occur
Reading Files: Simple Example
Reading an Entire File
with open("example.txt", "r") as file: # Read all content at once
content = file.read() print(content)
Reading Line by Line
with open("example.txt", "r") as file: # Loop through each line
for line in file:
print(line.strip())
Reading File into list
with open("example.txt", "r") as file: # Loop through each line
for line in file:
print(line.strip())
Reading line by line is more memory-efficient for large files, as it processes only
Writing to Files: Basic Usage
Open in Write Mode Write Content File Is Saved
Content is written and file is
with open("output.txt", "w") file.write("Hello, Python!") automatically closed when the with
as file: block ends
The write() method adds string data
The "w" mode creates a new file or to the file
overwrites an existing one
Warning: Write mode will erase any existing content in the file!
Appending Data to Files
Example: Log File
import datetimewith open("app_log.txt", "a") as log_file:
timestamp = datetime.datetime.now()
log_entry = f"{timestamp}:
Application started\n"
log_file.write(log_entry)
The "a" mode preserves existing content and adds new data at the end of the file
Append mode is perfect for logs, data collection, and any scenario where you need
Deleting Files: Simple Example
Using os Module to Check File Existence
import os
if os.path.exists("example.txt"):
print("File exists.")
else:
print("File does not exist.")
Deleting a File
import os
if os.path.exists("example.txt"):
os.remove("example.txt")
print("File deleted.")
else:
print("File not found.")
Using Try-Except While Handling Files
try:
with open("example.txt", "r") as file:
print(file.read())
except FileNotFoundError:
print("File not found!")
Reading line by line is more memory-efficient for large files, as it processes only
Download a file and unzip a zipped file
Downloading a file Unzipping a file
def unzip_file(save_path):
import requests # Specify the path to your zip file
import zipfile zip_file_path = save_path
import os
# Specify the directory where you want to extract the contents
(optional)
def download_file(file_url,save_path): # If not provided, contents will be extracted to the current working
bflag = False directory.
try: extraction_path = '.\\'
response = requests.get(file_url, stream=True) # Use
stream=True for large files with zipfile.ZipFile(zip_file_path, 'r') as zip_ref:
response.raise_for_status() # Raise an exception for bad zip_ref.extractall(extraction_path)
status codes (4xx or 5xx)
'''
with open(save_path, 'wb') as file: if os.path.exists("standard_rating.zip"):
for chunk in response.iter_content(chunk_size=8192): os.remove("standard_rating.zip")
file.write(chunk) print("File deleted.")
else:
print(f"File downloaded successfully to: {save_path}")
print("File not found.")
bflag = True '''
except requests.exceptions.RequestException as e:
print(f"Error during download: {e}") print(f"Contents of '{zip_file_path}' extracted to
bflag = False '{extraction_path}’”)
except Exception as e:
print(f"An unexpected error occurred: {e}")
bflag = False if __name__ == '__main__':
save_path = "standard_rating.zip" # Name and path for the
if __name__ == '__main__': downloaded file
file_url = if os.path.exists("standard_rating.zip"):
print("File exists.")
"http://ratings.fide.com/download/standard_rating_list_xml.zip" #
unzip_file(save_path)
Replace with the actual URL
else:
save_path = "standard_rating.zip" # Name and path for the print("File does not exist.")
downloaded file
bflag = download_file(file_url,save_path)
Best Practices in File Management
Always Use Context Managers Process Large Files Efficiently
The with statement ensures files are properly closed Read and process large files line by line instead of
even if exceptions occur loading them entirely into memory
Use Proper Error Handling Validate File Paths
Anticipate and handle potential file operation errors Use os.path or pathlib to check if files exist before
with try-except blocks attempting operations
Why Do Exceptions Occur in File Handling?
File Not Found Permission Issues System Issues
The specified file doesn't exist at Your program lacks the necessary Disk errors, network failures, or
the given path rights to access or modify the file other hardware/OS problems
Introduction to Exception Handling
Basic Structure
try:
# Code that might raise an exception
file = open("config.txt", "r")
data = file.read()
except:
# Code that runs if an exception occurs
print("An error occurred!")
finally:
# Code that always runs, error or not
if 'file' in locals():
file.close()
Exception handling prevents your program from crashing when errors occur,
FileNotFoundError: Example and Explanation
What Triggers This Error?
• Trying to open a file that doesn't exist
• Incorrect path specification
• Typos in filename
# This will raise FileNotFoundErrorwith
open("missing.txt", "r") as file:
content = file.read()
FileNotFoundError is a subclass of OSError and occurs when Python cannot locate
Handling FileNotFoundError in Code
try: with open("user_data.txt", "r") as file:
user_info = file.read()
process_user_data(user_info)
except FileNotFoundError:
print("User data file not found!")
Key Benefits
• Program continues running despite the error
• User sees a helpful message instead of a crash
• Alternative actions can be taken automatically
• Opportunity to recover from the error
PermissionError: What and Why
Protected Files Read-Only Resources
Attempting to modify system files Trying to write to a file marked as read-
without admin rights only
Network Restrictions User Permissions
Writing to network locations without Accessing files owned by another user
proper authentication account
# Example that might raise PermissionErrorwith
open("/etc/passwd", "w") as file: # System file on Unix/Linux
file.write("This will fail without root privileges")
General I/O Errors: IOError
Disk Full Errors
No space left on device to write data
Corrupted Files
File structure is damaged and cannot be read properly
Network Timeouts
Remote file operations timing out due to connection issues
Hardware Failures
Physical storage device problems preventing access
Note: In modern Python, IOError is now an alias for OSError.
Catching Multiple File Exceptions
try:
with open("important_data.txt", "r") as file:
data = file.read()
process_data(data)
except FileNotFoundError:
print("Data file is missing! Check your file path.")
create_empty_data_file()
except PermissionError:
print("You don't have permission to access this file.")
request_admin_access()
except IOError:
print("A hardware or system error occurred.")
log_error_details()
except Exception as e:
print(f"An unexpected error occurred: {e}")
send_error_report()
Arrange exceptions from most specific to most general. Always handle specific exceptions
before catching general ones.
The Finally Block: Ensuring Cleanup
Purpose of Finally
• Execute cleanup code regardless of exceptions
• Close resources even if errors occur
• Ensure consistency in program state
file = None
try:
file = open("data.txt", "r")
content = file.read()
process_data(content)
except FileNotFoundError:
print("File not found!")
finally:
if file is not None:
file.close()
print("File closed successfully")
The finally block executes whether an exception occurred or not, making it perfect for resource
Defensive Programming Strategies
Validate Inputs First 1
import os
if os.path.exists("data.txt"): 2 Check Permissions Before Access
with open("data.txt", "r") as f:
data = f.read()
import os
else:
print("File not found. Creating empty file...")
file_path = "config.ini"
with open("data.txt", "w") as f:
if os.access(file_path, os.W_OK):
f.write("")
with open(file_path, "w") as f:
Implement Comprehensive Logging 3 f.write("debug=True\n")
else:
print(f"No write permission for {file_path}")
import logging
logging.basicConfig(filename="app.log",
level=logging.INFO)
try:
with open("data.txt", "r") as f:
data = f.read()
except Exception as e:
logging.error(f"Error processing file: {e}")
raise
Useful Real-World Patterns
Robust Batch File Processing Automatic Backup Before Writing
import shutil
def process_files(file_list):
import os
results = []
errors = []
def safe_write(filename, data):
# Create backup if file exists
for filename in file_list:
if os.path.exists(filename):
try:
backup = filename + ".bak"
with open(filename, "r") as f:
shutil.copy2(filename, backup)
data = f.read()
print(f"Backup created: {backup}")
result = process_data(data)
results.append((filename, result))
try:
except Exception as e:
with open(filename, "w") as f:
errors.append((filename, str(e)))
f.write(data)
# Log error but continue processing
return True
continue
except Exception as e:
print(f"Write failed: {e}")
# Report summary
# Restore from backup if write failed
print(f"Processed {len(results)} files successfully")
if os.path.exists(filename + ".bak"):
print(f"Encountered {len(errors)} errors")
shutil.copy2(filename + ".bak", filename)
print("Restored from backup")
return results, errors
return False
class FileFormatError(Exception):
User-Defined Exceptions in File Handling """Raised when file format is incorrect"""
pass
Creating Custom Exceptions class ConfigError(Exception):
def __init__(self, message="A custom error occurred"):
self.message = message
Custom exceptions in Python are user-defined error types
super().__init__(self.message)
that allow developers to handle specific error conditions
in a more meaningful and organized way. While Python def __str__(self):
provides a variety of built-in exceptions like ValueError return f"Custom Error: {self.message}"
or TypeError, custom exceptions enable the creation of pass
tailored error messages and behaviors that align with the def read_config(filename):
unique requirements of an application. try:
with open(filename, "r") as f:
content = f.read()
Custom exceptions provide several benefits: if not content.strip().startswith("[CONFIG]"):
• More specific error information raise FileFormatError(
• Better organization of error types "Invalid config file format")
• Application-specific error handling
• Improved debugging experience # Parse configuration...
• They are particularly valuable in larger
applications where generic Python exceptions may not except FileNotFoundError:
provide enough context about what went wrong. raise ConfigError("Config file not found")
except FileFormatError as e:
raise ConfigError(f"Format error: {e}")
if __name__ == '__main__':
try:
read_config("data.txt")
except ConfigError as e:
print(f"Caught an error: {e}")
Conclusion and Key Takeaways
Master Fundamentals
1 Opening, reading, writing, and closing files
Use Context Managers
2 Always use with statements to ensure proper file handling
Handle Exceptions
3 Anticipate errors and implement specific exception handling
Apply Best Practices
4 Validate paths, check permissions, and implement logging for robust file operations
Build Resilient Applications
5 Combine file handling with exception management to create programs that gracefully
handle any file-related situation