1. File Handling with with
Statements: Error Handling and Resource Management
The with
statement provides a clean and efficient way to handle files, automatically closing them even if errors occur. This prevents resource leaks and simplifies error handling.
try:
with open("my_file.txt", "r") as f:
= f.read()
contents # Process the file contents
print(contents)
except FileNotFoundError:
print("File not found!")
except Exception as e:
print(f"An error occurred: {e}")
This code elegantly manages the file, ensuring it’s closed regardless of success or failure.
2. Working with Different File Modes
Python offers various file modes beyond the common “r” (read) and “w” (write). Understanding these modes is essential for flexible I/O operations:
"a"
(append): Adds data to the end of an existing file."x"
(exclusive creation): Creates a new file and fails if the file already exists."b"
(binary): Used for working with binary files (images, audio, etc.)."t"
(text): Used for working with text files (default). This mode handles text encoding.- Combining modes (e.g.,
"r+"
,"w+b"
): Allows both reading and writing.
#Append to a file
with open("my_file.txt", "a") as f:
"\nThis line is appended.")
f.write(
#Write in binary mode
with open("image.jpg", "rb") as f:
= f.read() image_data
3. Efficient I/O with Buffers
For large files, using buffers can significantly improve performance. Buffers store data temporarily before writing it to disk, reducing the number of disk access operations.
import io
= 4096 # Adjust as needed
buffer_size
with open("large_file.txt", "r") as f:
while True:
= f.read(buffer_size)
chunk if not chunk:
break
# Process the chunk
print(f"Processing chunk: {len(chunk)} bytes")
#Using io.BufferedIOBase for more control over buffering
with open("large_file.txt", "r") as f:
= io.BufferedReader(f)
buffered_file #process buffered_file.read(buffer_size)
4. Object Serialization and Deserialization (Pickling)
Python’s pickle
module allows you to serialize Python objects (convert them into a byte stream) and deserialize them (convert them back into objects). This is extremely useful for saving and loading complex data structures.
import pickle
= {"name": "John Doe", "age": 30, "city": "New York"}
data
#Serialization
with open("data.pickle", "wb") as f:
pickle.dump(data, f)
#Deserialization
with open("data.pickle", "rb") as f:
= pickle.load(f)
loaded_data print(loaded_data)
Remember that pickle
is not secure for untrusted data.
5. Working with CSV Files
The csv
module provides tools for easily reading and writing CSV (Comma Separated Values) files.
import csv
= [["Name", "Age", "City"], ["John", "30", "New York"], ["Jane", "25", "London"]]
data
with open("data.csv", "w", newline="") as f:
= csv.writer(f)
writer
writer.writerows(data)
with open("data.csv", "r") as f:
= csv.reader(f)
reader for row in reader:
print(row)
6. Handling Large Files with Generators
For extremely large files that don’t fit into memory, using generators is crucial. Generators yield data piece by piece, avoiding memory overload.
def read_large_file(filename, chunk_size=1024):
with open(filename, 'r') as f:
while True:
= f.read(chunk_size)
chunk if not chunk:
break
yield chunk
for chunk in read_large_file("massive_file.txt"):
#process chunk
pass