Previous | Tutorial index | Next

Tutorial 6: File Handling – Text Files vs. Binary Files

Learning Objectives

Overview

Files are the primary means of persistent data storage on a computer. Python provides a rich set of tools to read from and write to files, whether they contain human‑readable text (like .txt, .csv, .json) or raw binary data (images, audio, executables, etc.). This tutorial covers everything you need to know to work with files safely and efficiently.

We will start with the open() function, explore the various file modes, and then dive deep into the differences between text and binary files. You will learn the essential methods for reading and writing, the importance of specifying character encodings, and the use of the with statement for automatic resource management. We’ll also touch on handling file paths and common pitfalls.

1. Opening Files – The open() Function

The built‑in open() function is your gateway to file I/O. It returns a file object (also called a file handle) that provides methods for reading, writing, and closing the file.

file = open('example.txt', 'r') # open for reading (default mode) # ... do something with file ... file.close() # always close when done!

However, relying on manual .close() is error‑prone – exceptions can leave the file open. The context manager with is the recommended way.

1.1 File Modes – A Detailed Look

The second argument to open() is the mode, a string that specifies how the file will be used. The most common are:

Mode Description
'r' Read (default). Opens the file for reading; raises FileNotFoundError if the file does not exist.
'w' Write. Opens for writing; overwrites the file if it exists, or creates a new one if it doesn’t.
'a' Append. Opens for writing; data is appended to the end of the file; creates the file if it doesn’t exist.
'x' Exclusive creation. Opens for writing, but fails with FileExistsError if the file already exists.
'r+' Read and write (must exist).
'w+' Write and read (overwrites existing).
'a+' Append and read (append at end).

Additionally, you can combine modes with the following modifiers:

1.2 Specifying Encoding for Text Files

When you open a file in text mode (the default), Python decodes the bytes into strings using a specific character encoding. The default encoding is platform‑dependent (locale.getpreferredencoding()), which may cause compatibility issues. It is best practice to explicitly specify an encoding, usually 'utf-8'.

with open('example.txt', 'r', encoding='utf-8') as f: content = f.read()

If you try to read a file with the wrong encoding, you will encounter a UnicodeDecodeError. We’ll discuss handling encoding errors later.

1.3 The with Statement – Safe File Handling

The with statement (a context manager) ensures that the file is properly closed after the block is exited, even if an exception occurs.

with open('data.txt', 'w', encoding='utf-8') as f: f.write('Hello, world!') # File is automatically closed here.

You can also open multiple files in one with:

with open('source.txt', 'r') as src, open('dest.txt', 'w') as dst: dst.write(src.read())

2. Text Files vs. Binary Files – The Core Difference

2.1 Text Files

2.2 Binary Files

2.3 When to Use Which?

3. Essential File Methods

3.1 Reading Methods

Method Description
read(size=-1) Reads size characters (text) or bytes (binary). If size is omitted or negative, reads the entire file.
readline(size=-1) Reads one line up to size characters/bytes. Returns an empty string when EOF is reached.
readlines(hint=-1) Reads all lines and returns a list of strings (text) or bytes (binary). hint can limit the total number of lines read.

Example – text file:

with open('poem.txt', 'r', encoding='utf-8') as f: for line in f: # iterating over the file object reads line by line print(line.strip())

Example – binary file:

with open('image.png', 'rb') as f: data = f.read(1024) # read first 1024 bytes while data: # process data... data = f.read(1024)

3.2 Writing Methods

Method Description
write(s) Writes the string s (text mode) or bytes‑like object s (binary mode). Returns the number of characters/bytes written.
writelines(lines) Writes a list (or any iterable) of strings/bytes to the file. Does not automatically add line breaks – you must include them.

Example:

lines = ["First line\n", "Second line\n"] with open('output.txt', 'w', encoding='utf-8') as f: f.writelines(lines)

3.3 Seeking and Telling

For random access, you can move the file position:

with open('data.bin', 'rb') as f: f.seek(10) # move to byte 10 from start byte = f.read(1) # read the 11th byte

3.4 Other Useful Methods

4. Handling File Paths

4.1 Absolute vs. Relative Paths

You can get the current working directory with os.getcwd() and change it with os.chdir().

4.2 Using os.path and pathlib

The os.path module provides functions for manipulating paths in a platform‑independent way:

The newer pathlib module (Python 3.4+) offers an object‑oriented approach:

from pathlib import Path p = Path('data/input.txt') print(p.exists()) print(p.parent) # data with p.open('r', encoding='utf-8') as f: content = f.read()

pathlib is recommended for new code.

5. Working with Encodings – Common Pitfalls

5.1 Specifying Encoding

Always specify encoding when opening text files. For maximum compatibility, use 'utf-8' or 'utf-8-sig' (for files with a BOM – byte order mark, often from Windows tools).

# Write with explicit encoding with open('file.txt', 'w', encoding='utf-8') as f: f.write('unicode ✓')

5.2 Handling Encoding Errors

When reading a file with the wrong encoding, Python raises UnicodeDecodeError. You can handle this by specifying the errors parameter:

with open('problematic.txt', 'r', encoding='ascii', errors='replace') as f: content = f.read() # malformed chars become '�'

5.3 Detecting Encoding

Sometimes you don't know the encoding. The chardet library can help detect it, but it's not built‑in.

6. Common Patterns and Examples

6.1 Reading a Text File Line by Line

with open('log.txt', 'r', encoding='utf-8') as f: for line in f: if 'ERROR' in line: print(line.strip())

6.2 Writing a CSV‑like File

data = [['Name', 'Age'], ['Alice', 30], ['Bob', 25]] with open('people.csv', 'w', encoding='utf-8') as f: for row in data: f.write(','.join(str(cell) for cell in row) + '\n')

6.3 Copying a Binary File (efficient chunk‑wise)

def copy_file(src, dst): with open(src, 'rb') as src_f, open(dst, 'wb') as dst_f: while True: chunk = src_f.read(4096) # 4KB chunks if not chunk: break dst_f.write(chunk)

6.4 Appending to a Text File

with open('log.txt', 'a', encoding='utf-8') as f: f.write(f'Error: {error_msg}\n')

6.5 Reading the Last N Lines (Using seek and looping from the end) – more advanced

def tail(filename, n=10): with open(filename, 'rb') as f: f.seek(0, 2) # go to end size = f.tell() block = 1024 lines = [] while len(lines) <= n and size > 0: f.seek(max(0, size - block), 0) data = f.read(block) lines = data.splitlines() + lines size -= block return lines[-n:]

7. Exception Handling with Files

File operations can raise exceptions:

It is good practice to catch these errors:

try: with open('data.txt', 'r', encoding='utf-8') as f: content = f.read() except FileNotFoundError: print("File not found.") except PermissionError: print("Permission denied.") except Exception as e: print(f"An error occurred: {e}")

📝 Quiz – Check Your Understanding

  1. Which mode should you use to open a text file for reading, and you want to raise an error if the file does not exist?

    Answer(A) `'r'`
  2. True or False: When you open a file in binary mode, you do not need to specify an encoding.

    AnswerTrue
  3. What is the purpose of the with statement in file handling?

    Answer(B) To automatically close the file after the block ends.
  4. What method reads the entire contents of a file as a string (in text mode)?

    Answer(B) `read()`
  5. Which method writes a list of strings to a file without automatically adding line breaks?

    Answer(B) `writelines()`
  6. What encoding is recommended for maximum portability?

    Answer(C) `'utf-8'`
  7. What does file.tell() return?

    Answer(B) The current file position from the beginning.
  8. Which mode would you use to open a binary file for reading?

    Answer(B) `'rb'`
  9. What exception is raised when you try to open a non‑existent file in read mode?

    Answer(A) `FileNotFoundError`
  10. How do you append text to the end of an existing text file without erasing its content?

    Answer(B) Use mode `'a'`

💻 Exercises – Practice Makes Perfect

Exercise 1: Greeting File
Write a program that:

Sample Solution ```python name = input("Name: ") age = input("Age: ") with open('greeting.txt', 'w', encoding='utf-8') as f: f.write(f"Hello {name}, you are {age} years old.") with open('greeting.txt', 'r', encoding='utf-8') as f: print(f.read()) ```

Exercise 2: Line Numbering
Write a script that reads a text file input.txt and writes a new file numbered.txt where each line is prefixed with its line number.

Sample Solution ```python with open('input.txt', 'r', encoding='utf-8') as infile, \ open('numbered.txt', 'w', encoding='utf-8') as outfile: for i, line in enumerate(infile, start=1): outfile.write(f"{i}: {line}") ```

Exercise 3: Binary File Copy
Write a function copy_binary(src, dst, chunk_size=1024) that copies a binary file in chunks.

Sample Solution ```python def copy_binary(src, dst, chunk_size=1024): with open(src, 'rb') as src_f, open(dst, 'wb') as dst_f: while True: chunk = src_f.read(chunk_size) if not chunk: break dst_f.write(chunk) ```

Exercise 4: Word Counter
Read a text file, count words, lines, and characters, and write statistics to stats.txt.

Sample Solution ```python with open('sample.txt', 'r', encoding='utf-8') as f: content = f.read() lines = content.splitlines() words = content.split() chars = len(content) with open('stats.txt', 'w', encoding='utf-8') as f: f.write(f"Lines: {len(lines)}\nWords: {len(words)}\nCharacters: {chars}\n") ```

Exercise 5: CSV Reader with Dict
Given a CSV file students.csv with columns Name,Math,Science,English, read it, compute averages per student and per subject, and print.

Sample Solution ```python import csv with open('students.csv', 'r', encoding='utf-8') as f: reader = csv.DictReader(f) rows = list(reader) for row in rows: avg = (int(row['Math']) + int(row['Science']) + int(row['English'])) / 3 print(f"{row['Name']}: {avg:.2f}") # Subject averages math_avg = sum(int(r['Math']) for r in rows) / len(rows) # etc. ```

🏠 Homework – Deeper Thinking

Short Answer Questions

1. Log File Analyzer
Given a log file with lines timestamp,level,message, count levels, print summary, and write ERROR lines to errors.log.

Sample Answer ```python level_counts = {'INFO':0, 'WARNING':0, 'ERROR':0} errors = [] try: with open('server.log', 'r', encoding='utf-8') as f: for line in f: parts = line.strip().split(',', 2) if len(parts) == 3: ts, level, msg = parts if level in level_counts: level_counts[level] += 1 if level == 'ERROR': errors.append(line) except FileNotFoundError: print("File not found. Please specify another file.") # Print summary and write errors with open('errors.log', 'w', encoding='utf-8') as f: f.writelines(errors) ```

2. Find and Replace in File
Write a script that reads a file, replaces all occurrences of a search string, and overwrites the file.

Sample Answer ```python filename = input("Filename: ") search = input("Search: ") replace = input("Replace: ") with open(filename, 'r', encoding='utf-8') as f: content = f.read() new_content = content.replace(search, replace) with open(filename, 'w', encoding='utf-8') as f: f.write(new_content) ```

3. Directory Tree Lister
Recursively list all files and sizes in a directory with indentation.

Sample Answer ```python from pathlib import Path def list_dir(path, indent=0): for item in Path(path).iterdir(): print(' ' * indent + item.name, end='') if item.is_file(): print(f" ({item.stat().st_size} bytes)") else: print() list_dir(item, indent+1) ```

4. Binary File Integrity Checker (Checksum)
Calculate SHA‑256 hash and verify.

Sample Answer ```python import hashlib def hash_file(filename): h = hashlib.sha256() with open(filename, 'rb') as f: for chunk in iter(lambda: f.read(4096), b''): h.update(chunk) return h.hexdigest() # Write hash to file, then verify ```

Essay Questions

5. CSV to JSON Converter
Write a function csv_to_json(csv_filename, json_filename) using csv and json modules.

Sample Answer ```python import csv, json def csv_to_json(csv_filename, json_filename): with open(csv_filename, 'r', encoding='utf-8') as csv_f: reader = csv.DictReader(csv_f) data = list(reader) with open(json_filename, 'w', encoding='utf-8') as json_f: json.dump(data, json_f, indent=2) ```

Homework Hints

Summary

In this tutorial, you have learned:

With these skills, you can handle persistent data storage in your Python applications, from simple configuration files to complex binary data processing.

Next Steps: In Tutorial 7, we will cover Exception Handling in depth, learning how to anticipate, catch, and manage errors gracefully across your codebase.

Happy file handling!

Previous | Tutorial index | Next