File input and output: the way your Python program talks to files on your computer's hard drive — reading data in and writing data out. Without it, your program is a lonely kitchen with no way to receive recipes (data) or save the meals it cooks (results). For the PCAP-31-03 exam, you must be able to open files correctly, read and write both text and binary data, and use the with statement to manage resources safely — because a file left open can corrupt data or crash your program.
Jump to a section
A simple way to picture File Input/Output: Reading, Writing, and Context Managers
A restaurant waiter is the person who manages the flow of food and information between the kitchen and the customers. In file input/output, your Python program is like the kitchen, the file on disk is like the customer's order slip, and the waiter is the file handle — the object that connects your code to the data.
When a customer places an order, the waiter doesn't just shout the order across the room. They take the slip (open the file), carry it to the kitchen, and stand there while the chef reads it (read the file). Once the chef has the information, the waiter doesn't stay forever — they go back to the dining room and, crucially, they don't leave the order slip lying on the kitchen counter. That would be a health-code violation (a resource leak). Instead, they properly file the slip away (close the file) so the next order can be taken.
Now, imagine the waiter uses a tray with a lid — that's the "with" statement, also called a context manager. Even if the chef drops the pan (an error occurs in your code), the lid stays on the tray, and the waiter still cleans up properly and hands the slip back to the customer. Without the tray lid, if the chef panics, food flies everywhere, and the waiter might forget to file the slip. The context manager guarantees cleanup happens, no matter what.
This maps exactly to Python: you open a file with open(), you read or write data, and you must close() it. The with statement acts as the tray lid, automatically closing the file for you, even if an error interrupts your program.
File input and output (I/O) is how your Python program reads data from storage and writes data to storage. Storage means your hard drive or solid-state drive (SSD) — the place where data stays even when the computer is turned off. When you work with files, you are creating a bridge between your running program (which lives in RAM, temporary memory) and a permanent location on disk.
First, you need to understand what a file is. A file is a named collection of bytes stored on a filesystem. The filesystem is the structure your operating system uses to organise files into directories (like folders on your desktop). Every file has a name (like "data.txt") and a location (a path on disk, such as /home/user/data.txt on Linux or C:\Users\User\data.txt on Windows).
To work with a file in Python, you must open it. Opening a file creates a connection between your Python program and that file on disk. This connection is called a file object or file handle. You create a file object using the built-in open() function. The open() function takes two main arguments: the filename (a string) and the mode (another string that tells Python what you want to do with the file). The mode is one or two characters that specify the operation. The most common modes are:
'r' for reading text (the default if you don't specify a mode)
'w' for writing text (creates a new file or overwrites an existing one)
'a' for appending text (adds data to the end of an existing file)
'x' for exclusive creation (creates a new file but raises an error if the file already exists)
'b' for binary mode (add 'b' to the mode, like 'rb' for reading binary or 'wb' for writing binary)
Binary files store data as raw bytes — images, videos, executable programs. Text files store characters encoded in a format like UTF-8, which maps each character to a unique number.
Once the file is open, you can read content using methods like .read() (reads the entire file into a single string), .readline() (reads one line at a time), or .readlines() (reads all lines into a list of strings). To write, you use .write() or .writelines().
After you finish working with a file, you must close it using the .close() method. Closing a file tells the operating system that your program is done with that resource. If you forget to close a file, the operating system might keep the file locked, preventing other programs from accessing it. Worse, if your program crashes before closing, data you thought you wrote might still be sitting in a memory buffer, not yet saved to disk. This is called a resource leak — your program uses up system resources that are never freed.
The problem is that programmers often forget to call .close(), especially when their code has many branches or when an error occurs partway through. To solve this, Python offers a better way: the with statement, also known as a context manager.
A with statement looks like this:
with open('data.txt', 'r') as file: content = file.read() print(content)
When you use with, Python automatically calls .close() on the file object as soon as the indented block of code finishes, even if an error occurs inside the block. This is safe and predictable. Context managers are not limited to files — they can manage any resource that needs setup and teardown (like network connections or locks). But for the PCAP exam, you only need to know how they work with files.
There are also different ways to read and write binary data. Binary mode is critical for files that are not human-readable text — for example, an image or a compiled Python .pyc file. When you open a file in binary mode (e.g., 'rb' or 'wb'), Python returns the data as bytes objects instead of strings. You cannot read or write strings directly in binary mode — you must work with bytes.
Finally, remember that file I/O can fail. If you try to open a file that does not exist in read mode, Python raises a FileNotFoundError. If you try to write to a file without permission, you get a PermissionError. The exam expects you to handle these exceptions gracefully, often with try/except blocks.
1. Choose the File and Path
Decide which file you want to work with and where it is located. Provide the full or relative path as a string to the open() function. A relative path is relative to your program's current working directory. An absolute path starts from the root of the filesystem (e.g., /home/user/data.txt on Linux).
2. Choose the Mode
Select the mode string based on what you want to do: 'r' for reading, 'w' for writing (overwrite), 'a' for appending, 'x' for exclusive creation. Add 'b' for binary (e.g., 'rb' for reading binary, 'wb' for writing binary). The mode determines what operations are allowed on the file handle.
3. Open the File with a with Statement
Use the with keyword followed by open(filename, mode) and assign the result to a variable with as. This creates the file handle and ensures cleanup when the indented block ends. Example: with open('data.txt', 'r') as f:
4. Perform File Operations
Inside the with block, call methods on the file handle to read or write data. For reading: .read() reads entire content, .readline() reads one line, .readlines() returns a list of lines. For writing: .write(data) writes a string or bytes. The file pointer moves as you read/write.
5. Let the with Statement Close the File
When the with block finishes (normally or due to an exception), the file is automatically closed. You do not call .close() manually. After the block, the file handle is closed — you cannot read or write through it, but the variable still exists and has attributes like .closed (True) and .name.
An IT professional — let's call her Priya, a junior data analyst — is asked to write a Python script that processes a log file from a web server. The log file contains one line per request, recording things like IP addresses, timestamps, and HTTP status codes. This file is stored on a shared network drive, and it's updated every hour. Priya's task is to read the file, filter out all lines where the status code is 500 (meaning a server error), and write those filtered lines into a new report file named "errors_today.csv".
Here is how Priya would approach it step by step.
First, she opens the original log file in read mode. She uses a with statement so the file is guaranteed to close properly, even if something goes wrong. She specifies the filename with a full path: with open('/shared/logs/server.log', 'r') as log_file:
Inside the with block, she reads all lines using .readlines(). This gives her a list where each element is a single line from the log file. She then loops over each line. For each line, she uses .split() to break it into fields based on spaces. The status code is the 8th field (index 7 if using zero-based indexing). She checks if that field equals '500'. If it does, she appends the line to a list called error_lines.
Once the loop finishes, she opens the output file in write mode: with open('errors_today.csv', 'w') as out_file:
Inside this block, she writes each error line to the output file using .write(). She could also use .writelines() to write the whole list at once.
Now, what could go wrong in the real world? The log file might be enormous — gigabytes of data. Using .read() to read it all at once could crash the program because it would try to load everything into memory. An experienced IT professional would read the file line by line using a simple for loop (for line in log_file:) without calling .readlines(). This reads one line at a time from disk, using very little memory. The exam tests this pattern.
Priya also considers error handling. What if the log file is currently being written to by the web server? She might get a PermissionError. She wraps her file operations in a try/except block. If she encounters an error, she logs it to a separate error file or prints a message, rather than crashing the entire script.
After writing the CSV file, Priya runs a quick sanity check by opening the output file in read mode and printing the first 5 lines. This confirms the script worked correctly.
This scenario shows the real power of file I/O: data processing. IT professionals use file I/O daily for log analysis, configuration file parsing, generating reports, importing/exporting data between systems, and managing backups — all using the same basic open/read/write/close pattern.
The PCAP-31-03 exam tests objective 3.3 in a straightforward but detail-oriented way. You need to know exactly how open(), read(), write(), and close() work, and you must be able to recognise the correct syntax for the with statement. The exam questions are usually multiple-choice, single-answer, or fill-in-the-blank. They rarely ask you to write a full program; instead, they give you a snippet of code and ask: "What will this code output?" or "What is the correct way to...?"
Concepts they love to test:
The difference between text mode and binary mode. They will give you a code snippet that opens a file as 'r' when it should be 'rb', and ask what error occurs.
The default mode of open() is 'r' (text read). If you forget the mode argument, you are reading as text.
The behaviour of 'w' vs 'a' vs 'x': 'w' overwrites, 'a' appends, 'x' fails if file exists. They will ask you to predict the outcome.
The with statement: they want to see you recognise that after the with block, the file is automatically closed. A common trap is a question that asks if calling .close() inside a with block is necessary. The answer is no — it's redundant but not incorrect.
File reading methods: .read(), .readline(), .readlines(). They test the result type (string vs list) and behaviour (whether .readline() includes the newline character).
The .write() method returns the number of characters written. They rarely test this, but it's possible.
The .tell() and .seek() methods: .tell() returns the current file position (an integer byte offset), and .seek(offset, whence) moves the file position. You need to know that whence defaults to 0 (beginning of file), can be 1 (current position), or 2 (end of file). They might ask what .seek(0, 2) does — it moves to the end of the file, useful for appending or getting file size.
Exceptions: FileNotFoundError and PermissionError are common. They want you to know what exception is raised when opening a non-existent file for reading.
The encoding parameter: you can pass encoding='utf-8' to open() for text files. The exam may ask what happens if you open a text file without specifying encoding on a system with a different default (e.g., Windows vs Linux). The answer: Python uses the system default encoding, which can cause errors if the file uses a different encoding.
Traps they set:
They will present a code snippet that opens a file with 'w' and then immediately reads from it — a RuntimeError will be raised because you cannot read a file opened in write mode.
They will show code that calls .close() but then tries to use the file object — an AttributeError or ValueError occurs because the closed file object is invalid.
They will use .readlines() and ask what type the result is. Beginners often confuse it with .read() which returns a string.
They will give a scenario where a file is opened inside a function, and the function returns without closing the file. They ask whether the file is closed automatically when the function ends. The answer: no, the file does not close until garbage collection happens, which is unpredictable. This is why with is preferred.
Key definitions to memorise:
File handle: the Python object returned by open().
Context manager: an object that defines __enter__ and __exit__ methods, used with the with statement.
Resource leak: failing to free system resources after use, such as not closing a file.
Byte: the smallest unit of data storage, composed of 8 bits. A byte can represent one character in some encodings.
Text mode: data is decoded from bytes to str.
Binary mode: data is read/written as raw bytes.
Practise spotting the mode and method combination. If you see 'r' and .write(), it's wrong. If you see 'w' and .read(), it's wrong. If you see 'a' and .read(), it's wrong. These are the most common traps.
Always use the with statement to open files — it guarantees the file is closed automatically, even if an error occurs.
The open() function's default mode is 'r' (text read), so always specify the mode explicitly to avoid accidents.
Mode 'w' overwrites the entire file at open() time — it does not wait until you call .write().
In binary mode, you must work with bytes, not strings — use 'rb' or 'wb' and encode/decode manually if needed.
After reading a file with .read(), the file pointer is at the end — call .seek(0) to read from the beginning again.
FileNotFoundError is raised when opening a non-existent file in read mode; PermissionError is raised when you lack access rights.
These come up on the exam all the time. Here's how to tell them apart.
Text mode ('r', 'w', 'a')
Returns data as strings (str type).
Newline characters are translated to your OS default ( on Linux, on Windows).
Suitable for human-readable files like .txt, .csv, .html.
Binary mode ('rb', 'wb', 'ab')
Returns data as bytes objects.
No newline translation — raw bytes are preserved exactly.
Suitable for non-human files like .jpg, .exe, .pyc.
open() without with
You must manually call .close() to free the resource.
If an exception occurs before .close(), the file may remain open.
Code is more error-prone and requires a try/finally block for safety.
open() with with
Automatically calls .close() when the indented block ends.
Even if an exception occurs, the file is closed safely.
Cleaner, shorter, and preferred style in professional Python.
Mode 'w' (write)
Overwrites the entire file if it exists; if not, creates a new one.
File pointer starts at the beginning of the file.
Dangerous if you accidentally overwrite important data.
Mode 'a' (append)
Does not overwrite — adds data to the end of the file.
File pointer starts at the end of the file.
Safe for adding new data to existing files (e.g., log files).
.read()
Reads the entire file content into a single string.
Uses a lot of memory for large files.
Returns the whole content, including all newline characters.
.readline()
Reads one line at a time, including the trailing newline.
Memory-efficient for large files because only one line is held in memory.
Returns an empty string when the end of the file is reached.
Mistake
When you open a file for writing with 'w', the file is created only when you call .write().
Correct
When you open a file with 'w', the file is truncated (emptied) or created immediately at the time of the open() call, not when you write to it.
Newcomers think of 'open' as just preparing a connection, but 'w' mode actually destroys existing content the moment you call open(), before any write happens.
Mistake
After a with block finishes, the file object disappears and you cannot access it anymore.
Correct
The file object still exists after the with block, but it is closed. You cannot read or write through it, but you can still inspect its attributes like .name or .mode.
The with statement only calls .close() — it doesn't delete the object. Beginners assume the variable is gone or that the object is destroyed, but that's not the case.
Mistake
Reading a file with .read() and then calling .read() again will read new data if the file has grown.
Correct
After you call .read() once, the file pointer is at the end of the file. A second call to .read() returns an empty string because there is nothing left to read — unless you reset the pointer with .seek(0).
People imagine the file is re-read from the beginning each time, but file handles maintain a position cursor that moves as you read.
Mistake
If you open a file in binary mode, you can still write strings to it as long as you call .encode() first.
Correct
In binary mode, you must only write bytes objects. You cannot write a string directly even if you encode it — you must encode it into bytes first. But actually, you can write a bytes object only. Many beginners think open('wb') allows direct string writing if the string is small.
The distinction between str and bytes is subtle for new programmers. They expect Python to handle the conversion automatically, but binary mode explicitly avoids that.
Mistake
The .close() method is optional — Python will close the file automatically when the program ends.
Correct
Python does not guarantee automatic closure when the program ends. Relying on program exit to close files is unsafe because if an exception occurs earlier, the file may remain open. You should explicitly close or use with.
Some beginners see that their small scripts work without calling .close() and assume it is safe, not realising they are relying on garbage collection timing, which is not predictable.
Reveal each answer, then mark whether you got it right. Score 60%+ to unlock the next chapter.
The file remains open, consuming system resources. In small scripts it might not cause issues because the OS closes files when the program ends, but in long-running programs or if an exception occurs, you could leak file handles or lose data that was buffered but not yet written to disk.
Yes, you can open multiple files in a single with statement by separating them with commas: with open('a.txt', 'r') as f1, open('b.txt', 'w') as f2:. Python will automatically close all files when the block ends.
.read() returns the entire file content as a single string (including newline characters). .readlines() returns a list of strings, where each list element is one line (including the trailing newline).
FileNotFoundError occurs when you try to open a file in read mode that does not exist at the specified path. Check that the filename and path are correct, or use 'w' or 'x' mode to create a new file instead.
The 'b' means binary mode. When you open a file with 'rb', you are reading the file as raw bytes, not as text. The data is returned as a bytes object, not a string. Use binary mode for files that are not plain text, such as images or executable files.
You can, but you must open the file in a mode that allows both, such as 'r+' (read and write) or 'w+' (read and write, truncating first). However, doing so is tricky because the file pointer position matters. It is often simpler to open the file for reading, process the data, close it, then open it again for writing.
You've finished File Input/Output: Reading, Writing, and Context Managers. Continue through the PCAP-31-03 study guide to build a complete picture of the exam.
Done with this chapter?