Previous | Tutorial index | Next
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.
open() FunctionThe 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.
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:
'b' – binary mode (e.g., 'rb', 'wb').'t' – text mode (default, e.g., 'rt' is same as 'r').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.
with Statement – Safe File HandlingThe 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())
\r\n on Windows, \n on Unix) when in text mode..txt, .csv, .json, .xml, .html, .py.bytes objects..png, .jpg, .mp3, .pdf, .exe, .pyc.bytes; writing accepts bytes (or byte‑like objects).| 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)
| 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)
For random access, you can move the file position:
tell() – returns the current position (as an integer) from the beginning of the file.seek(offset, whence=0) – moves the position to offset bytes/characters from whence (0 = start, 1 = current, 2 = end).with open('data.bin', 'rb') as f:
f.seek(10) # move to byte 10 from start
byte = f.read(1) # read the 11th byte
flush() – forces the buffer to be written to disk (usually not needed, but useful for interactive programs).close() – closes the file; you should rarely need to call it directly if using with.fileno() – returns the underlying file descriptor (advanced).C:\Users\Name\data.txt on Windows, /home/name/data.txt on Linux).data.txt or ./data.txt).You can get the current working directory with os.getcwd() and change it with os.chdir().
os.path and pathlibThe os.path module provides functions for manipulating paths in a platform‑independent way:
os.path.join('dir', 'file.txt') – builds the correct path separators.os.path.exists(path) – checks if a file or directory exists.os.path.isfile(path) – checks if it is a file.os.path.isdir(path) – checks if it is a directory.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.
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 ✓')
When reading a file with the wrong encoding, Python raises UnicodeDecodeError. You can handle this by specifying the errors parameter:
errors='strict' – default, raises an error.errors='ignore' – silently skips problematic characters.errors='replace' – replaces them with a placeholder (e.g., �).errors='backslashreplace' – replaces with escaped sequences (like \u1234).with open('problematic.txt', 'r', encoding='ascii', errors='replace') as f:
content = f.read() # malformed chars become '�'
Sometimes you don't know the encoding. The chardet library can help detect it, but it's not built‑in.
with open('log.txt', 'r', encoding='utf-8') as f:
for line in f:
if 'ERROR' in line:
print(line.strip())
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')
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)
with open('log.txt', 'a', encoding='utf-8') as f:
f.write(f'Error: {error_msg}\n')
seek and looping from the end) – more advanceddef 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:]
File operations can raise exceptions:
FileNotFoundError – when opening a file for reading that doesn’t exist.PermissionError – when you don’t have the necessary permissions.IsADirectoryError – when you try to open a directory as a file.UnicodeDecodeError / UnicodeEncodeError – encoding issues.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}")
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?
'r''w''a''x'True or False: When you open a file in binary mode, you do not need to specify an encoding.
What is the purpose of the with statement in file handling?
What method reads the entire contents of a file as a string (in text mode)?
readline()read()readlines()write()Which method writes a list of strings to a file without automatically adding line breaks?
write()writelines()append()extend()What encoding is recommended for maximum portability?
'ascii''latin-1''utf-8''cp1252'What does file.tell() return?
Which mode would you use to open a binary file for reading?
'r''rb''rt''r+'What exception is raised when you try to open a non‑existent file in read mode?
FileNotFoundErrorPermissionErrorOSErrorIOErrorHow do you append text to the end of an existing text file without erasing its content?
'w''a''x''r+'Exercise 1: Greeting File
Write a program that:
greeting.txt.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.
Exercise 3: Binary File Copy
Write a function copy_binary(src, dst, chunk_size=1024) that copies a binary file in chunks.
Exercise 4: Word Counter
Read a text file, count words, lines, and characters, and write statistics to stats.txt.
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.
1. Log File Analyzer
Given a log file with lines timestamp,level,message, count levels, print summary, and write ERROR lines to errors.log.
2. Find and Replace in File
Write a script that reads a file, replaces all occurrences of a search string, and overwrites the file.
3. Directory Tree Lister
Recursively list all files and sizes in a directory with indentation.
4. Binary File Integrity Checker (Checksum)
Calculate SHA‑256 hash and verify.
5. CSV to JSON Converter
Write a function csv_to_json(csv_filename, json_filename) using csv and json modules.
str.startswith to identify log levels? Better: split by comma. Use a dictionary for counts.read(), then replace(), then seek to beginning and write, or write to a temp file and rename.pathlib.Path.rglob('*') or os.walk(). Keep track of depth for indentation.hashlib.sha256() and update with file content chunks to avoid memory issues.csv.DictReader – it yields dictionaries directly. Then json.dump() the list.In this tutorial, you have learned:
open() and the importance of the with statement.os.path and pathlib.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!