No history yet

Python File Handling

Managing Data with Files

Most programs need to save information so it can be used later. Instead of keeping everything in memory, which is temporary, we store data in files. Python gives you simple but powerful tools to create, read, and update files directly from your code.

The starting point for any file operation is the built-in open() function. It takes the file's name and an access mode as arguments and returns a file object, which acts as a link between your program and the file on your disk. Forgetting to close a file after you're done can lead to data corruption or resource leaks. The best practice is to use the with statement, which automatically handles closing the file for you, even if errors occur.

# Using the 'with' statement to open a file
# This is the recommended way to handle files.

with open('students.txt', 'w') as file:
    # 'w' mode is for writing. It creates the file if it doesn't exist.
    file.write('Rohan - Class 12\n')
    file.write('Priya - Class 12\n')

# The file is automatically closed here, outside the 'with' block.

Working with Text Files

Text files (.txt) are the simplest type of file. They store data as human-readable characters. You can interact with them using different access modes.

ModeDescription
'r'Read: Opens for reading. This is the default mode. Fails if the file doesn't exist.
'w'Write: Opens for writing. Creates the file if it doesn't exist. Overwrites the entire file if it already exists.
'a'Append: Opens for writing. Creates the file if it doesn't exist. Adds new data to the end of the file without overwriting existing content.
'r+'Read and Write: Opens for both reading and writing. The file pointer is at the beginning.

Once a file is open, you can use several methods to read its contents. read() gets the entire file content as a single string. readline() reads one line at a time, and readlines() reads all lines into a list of strings. For writing, write() adds a single string, while writelines() takes a list of strings and writes them to the file.

# Appending to our student list
with open('students.txt', 'a') as file:
    file.writelines(['Amit - Class 12\n', 'Sunita - Class 12\n'])

# Reading the data back
with open('students.txt', 'r') as file:
    # print(file.read()) # Reads the whole file
    lines = file.readlines() # Reads all lines into a list
    print(lines)

# Output:
# ['Rohan - Class 12\n', 'Priya - Class 12\n', 'Amit - Class 12\n', 'Sunita - Class 12\n']

Every open file has a pointer, which is like a cursor indicating where the next read or write operation will happen. You can control this pointer using the seek() and tell() methods.

tell() returns the current position of the pointer (as a number of bytes from the beginning of the file). seek(offset, from_where) moves the pointer. from_where can be 0 (start of file), 1 (current position), or 2 (end of file).

with open('students.txt', 'r') as file:
    print(f"Initial pointer position: {file.tell()}")
    
    # Read the first line
    first_line = file.readline()
    print(f"After reading one line: {file.tell()}")
    
    # Move the pointer back to the beginning
    file.seek(0)
    print(f"After seeking to start: {file.tell()}")
    
    # Read the whole file again
    content = file.read()
    print(content)

Binary Files and Pickling

While text files are great for strings, they can't store complex Python objects like lists, dictionaries, or custom objects directly. For that, we use binary files. These files store data in the same format (bytes) that the computer uses internally. You can't read them with a normal text editor.

To work with binary files, you add b to the access mode (e.g., rb for binary read, wb for binary write). To save Python objects, we use the pickle module. The process of converting an object into a byte stream is called pickling (or serialisation), and converting it back is unpickling.

import pickle

# Data to be stored
student_data = {
    'Rohan': {'roll_no': 1, 'marks': 95},
    'Priya': {'roll_no': 2, 'marks': 98}
}

# Pickling the dictionary to a binary file
with open('student_data.dat', 'wb') as file:
    pickle.dump(student_data, file)

# Unpickling the data from the file
with open('student_data.dat', 'rb') as file:
    loaded_data = pickle.load(file)
    print(loaded_data)

# Output:
# {'Rohan': {'roll_no': 1, 'marks': 95}, 'Priya': {'roll_no': 2, 'marks': 98}}

Handling CSV Files

CSV (Comma-Separated Values) files are a common format for storing tabular data, like spreadsheets. Each line in a CSV file is a data record, and each record consists of one or more fields, separated by commas. Python's csv module makes it easy to read and write this structured data without manually splitting strings.

import csv

# Writing to a CSV file
header = ['name', 'roll_no', 'marks']
data_rows = [
    ['Rohan', 1, 95],
    ['Priya', 2, 98],
    ['Amit', 3, 92]
]

with open('marks.csv', 'w', newline='') as file:
    writer = csv.writer(file)
    writer.writerow(header)
    writer.writerows(data_rows)

# Reading from a CSV file
with open('marks.csv', 'r') as file:
    reader = csv.reader(file)
    for row in reader:
        print(row)

# Output:
# ['name', 'roll_no', 'marks']
# ['Rohan', '1', '95']
# ['Priya', '2', '98']
# ['Amit', '3', '92']

Notice the newline='' argument when opening the file for writing. This is important to prevent blank rows from appearing in the CSV file on some operating systems.

For CSVs with headers, DictReader and DictWriter are even more convenient. DictReader reads each row as a dictionary where keys are taken from the header row, and DictWriter writes rows from a list of dictionaries.

import csv

# Writing with DictWriter
data_dicts = [
    {'name': 'Sunita', 'roll_no': 4, 'marks': 88},
    {'name': 'Vikram', 'roll_no': 5, 'marks': 90}
]

with open('marks_dict.csv', 'w', newline='') as file:
    fieldnames = ['name', 'roll_no', 'marks']
    writer = csv.DictWriter(file, fieldnames=fieldnames)
    writer.writeheader()
    writer.writerows(data_dicts)

# Reading with DictReader
with open('marks_dict.csv', 'r') as file:
    reader = csv.DictReader(file)
    for row in reader:
        print(row['name'], row['marks'])

# Output:
# Sunita 88
# Vikram 90

Graceful Error Handling

What happens if you try to read a file that doesn't exist? Your program will crash. File operations are prone to errors, such as FileNotFoundError or permission errors. To build robust programs, you must anticipate and handle these issues using try, except, and finally blocks.

The try block contains the code that might fail. The except block catches specific errors and runs only if that error occurs. The finally block contains code that runs no matter what, whether an error happened or not. It's perfect for cleanup tasks, like closing a file if you aren't using the with statement.

try:
    with open('non_existent_file.txt', 'r') as file:
        content = file.read()
        print(content)
except FileNotFoundError:
    print("Error: The file was not found.")
except Exception as e:
    # A general catch-all for other potential errors
    print(f"An unexpected error occurred: {e}")
finally:
    # This block always executes.
    print("File operation finished.")

# Output:
# Error: The file was not found.
# File operation finished.

Check your understanding of the key concepts from this section.

Quiz Questions 1/7

What is the primary advantage of using the with statement when working with files in Python?

Quiz Questions 2/7

Which access mode would you use to open a file for both reading and writing in binary format?

You now have the essential tools to manage data in text, binary, and CSV files using Python, preparing you for a wide range of programming challenges.