Courseiva
PCAP-31-03Chapter 10 of 17Objective 3.4

Working with the File System and Directories

Without knowing how to navigate and inspect files and directories in Python, you'll constantly hit a wall: your script crashes because it can't find a file, or it saves your new data to the wrong place, overwriting something important. For the PCAP-31-03 exam, you need to be comfortable using the os and pathlib modules to travel through folders, create new ones, check what's inside them, and verify whether a path points to a file or a directory.

12 min read
Intermediate
Updated Jul 23, 2026
Reviewed by Johnson Ajibi· Senior Network & Security Engineer · MSc IT Security

A simple way to picture Working with the File System and Directories

The Filing Cabinet Analogy

Your computer's file system works exactly like a giant filing cabinet you might find in an old office. Let's say you have one drawer that's labelled '2024 Projects'. Inside that drawer, you've got hanging folders for 'Client Reports', 'Internal Notes', and 'Budget Spreadsheets'. Inside the 'Client Reports' folder, there are individual manila folders — one for each client. Each manila folder holds actual papers: a letter, a printed spreadsheet, a signed contract.

When you open the top drawer, you're looking at the root of that drawer's universe. To get to the signed contract for 'Acme Corp', you move through a path: Drawer 1 -> Client Reports -> Acme Corp -> Signed Contract. In your computer, that path looks like: C:\2024 Projects\Client Reports\Acme Corp\signed_contract.pdf (on Windows) or /home/you/2024_Projects/Client_Reports/Acme_Corp/signed_contract.pdf (on Mac/Linux).

Now, Python gives you tools — the os module and the pathlib module — that let you do everything a filing clerk can do. The os module is like knowing the exact drawer number and folder label to grab something. The pathlib module is like having a smart assistant who understands that 'the signed contract in the Acme Corp folder' means the same thing, no matter which drawer system you're using. You can create new folders (hanging folders), rename files (replacing a paper with an updated version), check if a file exists (peeking into a folder to see if the contract is still there), and list all the files in a directory (pulling out every paper from a folder to see what you have). Without these tools, you'd have to manually memorise every single location — which is impossible when your filing cabinet has thousands of folders.

How It Actually Works

When you write a Python program that needs to read a configuration file, save user data, or process a set of images, you need to tell Python exactly where those files live on your computer's hard drive. This is the file system — the structured way your operating system organises files and folders (which are also called directories).

Think of the file system as a tree. The very top is called the root directory. On Windows, that's something like C:\. On macOS or Linux, it's just /. Underneath root, you have subdirectories (folders), and inside those, you have files. To point to one specific file, you use a path.

A path is simply the address of a file or folder. An absolute path starts from the root and gives the full address, like /home/anna/projects/data.csv. A relative path starts from wherever your Python program is currently running (its current working directory), like projects/data.csv.

Python provides two main modules to work with paths and the file system: os and pathlib. The os module (short for operating system) has been around for a long time. Its os.path submodule contains functions to manipulate paths. For example, os.path.join('home', 'anna', 'projects') will build the correct path string for your operating system. os.path.exists('data.csv') returns True or False. os.path.isfile('data.csv') checks if the path is a file, and os.path.isdir('projects') checks if it's a directory. To get a list of everything in a directory, you use os.listdir('.').

The pathlib module is newer and more object-oriented. Instead of dealing with strings, you create Path objects. For example, Path('data.csv').exists() does the same thing as os.path.exists('data.csv'). The big advantage is that you can use methods directly on the object, and it handles both Windows backslashes and Unix forward slashes automatically.

Here are the key operations you need for the exam:

Navigating: os.getcwd() tells you your current working directory. os.chdir('/new/path') changes it. With pathlib, Path.cwd() gives you the current directory as a Path object.

Creating: os.mkdir('new_folder') creates a single new directory. os.makedirs('parent/child/grandchild') creates all directories in that path if they don't exist. With pathlib, you use Path('new_folder').mkdir() and Path('parent/child/grandchild').mkdir(parents=True).

Inspecting: os.path.exists(path), os.path.isfile(path), os.path.isdir(path). With pathlib, Path(path).exists(), Path(path).is_file(), Path(path).is_dir().

Listing: os.listdir(path) returns a list of names of files and folders in that directory. pathlib offers Path.iterdir() which gives you an iterator of Path objects.

Renaming and deleting: os.rename(old, new) renames or moves a file. os.remove(filepath) deletes a file. os.rmdir(dirpath) deletes an empty directory. pathlib equivalents are Path.rename(target), Path.unlink(), and Path.rmdir().

Both modules do similar things, but pathlib is generally preferred in modern Python because it's cleaner and less prone to bugs from string manipulation. However, the exam tests both, so you need to recognise the syntax for each.

Why does all this matter? Because without it, you can't write a script that processes yesterday's log files, checks if a backup exists before overwriting it, or creates a folder structure for each new user. File system operations are the backbone of almost every practical Python program that deals with persistent data.

Flowchart showing the main file system operations in Python using os and pathlib modules.

Walk-Through

1

Import the required module

You need to import the module before using it. For os, write 'import os' or 'from os import path' for path functions. For pathlib, write 'from pathlib import Path'. This gives you access to all the file system functions.

2

Define a path

Create a path variable representing the file or directory you want to work with. With os, you typically use a string like 'data_folder/report.csv'. With pathlib, you create a Path object: 'p = Path('data_folder/report.csv')'. This path can be absolute or relative.

3

Check if the path exists and what it is

Before trying to read or write, verify the path exists using os.path.exists() or Path.exists(). Then check if it's a file or directory with os.path.isfile()/os.path.isdir() or Path.is_file()/Path.is_dir(). This prevents your script from crashing with a FileNotFoundError.

4

Create directories if needed

If your path points to a location that doesn't exist, create it. For a single new directory, use os.mkdir('new_folder') or Path('new_folder').mkdir(). For nested directories like 'parent/child/grandchild', use os.makedirs('parent/child/grandchild') or Path('parent/child/grandchild').mkdir(parents=True).

5

List or traverse the directory contents

To see what files and folders are in a directory, use os.listdir('path') which gives a simple list of names. For a recursive traversal of all subdirectories, use os.walk('path') which yields tuples of (root, dirs, files). With pathlib, use Path('path').iterdir() to iterate over entries as Path objects.

6

Perform file operations (rename, delete, move)

Once you've found the files you need, you can rename them with os.rename(old, new) or Path.rename(target). Delete a file with os.remove(filepath) or Path.unlink(). Delete an empty directory with os.rmdir(dirpath) or Path.rmdir(). For non-empty directories, use shutil.rmtree('path').

What This Looks Like on the Job

Imagine you work for a small marketing agency that runs weekly email campaigns. Every Monday, a script needs to generate personalised HTML email files based on customer data. Here's what an IT professional actually does with file system operations in Python:

First, the script checks if the output directory for this week's campaign exists. If it's week 44 of 2024, the script should save everything to /campaigns/2024/week44/. Using pathlib: if not Path('/campaigns/2024/week44/').exists(): Path('/campaigns/2024/week44/').mkdir(parents=True). This prevents errors when trying to write files into a non-existent folder.

Next, the script reads a CSV file of customer information from a centralised data directory. It uses os.path.join to build the path: data_file = os.path.join(data_dir, 'customers.csv'). This is safe because it respects the operating system's path separator.

Then, for each customer, the script needs to write a personalised HTML file. It creates the file path: output_path = Path(f'/campaigns/2024/week44/{customer_id}.html'). It writes the HTML content to that path. If a customer has previously opted out (a status flag in the CSV), the script should skip that customer and check if an old file for that customer exists to delete it. That's os.path.exists and os.remove in action.

After generating all files, the script needs to do a final sanity check — count how many HTML files were created and compare it to the number of customers processed. It uses os.listdir(output_dir) to get all file names, then filters for .html files using str.endswith() or Path.suffix.

Finally, the script archives the previous week's campaign folder to save space. It renames the folder from /campaigns/2024/week43 to /campaigns/2024/archive/week43. That's os.rename or Path.rename.

In a more complex scenario, the agency might have a shared network drive. The script must use os.path.isdir to check if a mounted network path is available before trying to read files. If the network is down, the script logs an error and exits gracefully instead of crashing with a FileNotFoundError.

Another real-world task: a system administrator writes a Python script to clean up old log files. The script walks through the /var/log directory tree, checks each file's modification time using os.path.getmtime, and deletes any .log file older than 30 days. This uses os.listdir, os.path.join, os.path.isfile, and os.remove in a loop. Without these file system tools, the admin would have to manually log into every server and delete files by hand — a waste of hours every week.

How PCAP-31-03 Actually Tests This

The PCAP-31-03 exam tests your ability to use both the os and pathlib modules for basic file system operations. Expect around 2-4 questions on this objective. They will not ask you to memorise every single function in both modules, but they will test your understanding of the common ones and the key differences between the two approaches.

Here are the specific concepts they love to test:

Recognising which function belongs to which module. For example, they might show you code like: import os; os.path.exists('test.txt') and ask what it does. A trap is that os.path.exists is in the os.path submodule, not os.exists(). Similarly, Path('test.txt').exists() belongs to pathlib.

The difference between absolute and relative paths. They might give you a code snippet that changes the current working directory with os.chdir, then uses a relative path, and ask you to predict the final path.

Creating directories with mkdir vs makedirs. They love to test that os.mkdir can only create a single directory and fails if parent directories don't exist, while os.makedirs creates intermediate directories too. With pathlib, Path.mkdir needs parents=True to act like makedirs.

The os.walk function — a powerful tool that recursively goes through every subdirectory. They may ask you to identify what a function like os.walk returns. It yields a tuple of (root_dir, list_of_subdirs, list_of_files).

Common traps and patterns:

Trap: Forgetting that os.remove() cannot delete a directory (use os.rmdir instead), and os.rmdir cannot delete a non-empty directory. With pathlib, Path.unlink() is for files, Path.rmdir() for empty directories.

Trap: Path manipulation on different operating systems. os.path.join('folder', 'subfolder') works cross-platform, but manually writing 'folder/' + 'subfolder' does not.

Trap: The pathlib Path object can be used with forward slashes even on Windows because Python converts them internally. So Path('data/file.txt') is fine.

Key definitions to memorise for the exam:

Current working directory (cwd): the directory your script is running from.

Absolute path: starts from the root (e.g., /home/user/file.txt or C:\Users\user\file.txt).

Relative path: starts from the current working directory (e.g., ../data/file.txt).

os.path.exists(path): returns True if the path exists.

os.path.isfile(path) and os.path.isdir(path): check type.

os.mkdir(path) vs os.makedirs(path): single vs recursive directory creation.

pathlib Path object: Path(path) creates an object with .exists(), .is_file(), .is_dir(), .mkdir(), .rename(), .unlink(), .rmdir() methods.

Expect multiple-choice questions where you must choose which code snippet correctly creates a directory structure, or which method checks if a path is a file. Some questions will present a scenario and ask you to identify the best module to use — pathlib is almost always the 'modern' answer.

Key Takeaways

The os module provides functions like os.path.exists(), os.path.isfile(), and os.mkdir() for string-based file system operations.

The pathlib module provides object-oriented Path objects with methods like Path.exists(), Path.is_file(), and Path.mkdir(parents=True).

os.makedirs() creates all intermediate directories in a path; os.mkdir() creates only the final directory and fails if parents are missing.

Use os.path.join() or the pathlib Path / operator to build cross-platform paths safely instead of string concatenation.

os.listdir() returns a list of filenames in a directory; os.walk() recursively traverses the entire directory tree.

A relative path depends on the current working directory (os.getcwd()), which can change during script execution.

os.remove() deletes files only; use os.rmdir() for empty directories or shutil.rmtree() for non-empty ones.

Easy to Mix Up

These come up on the exam all the time. Here's how to tell them apart.

os.path functions

Takes and returns plain strings for paths

Older, more verbose syntax

Requires importing os and os.path submodule

pathlib Path methods

Uses Path objects with method chaining

Newer, more Pythonic and readable syntax

Single import: from pathlib import Path

os.mkdir()

Can only create a single directory

Fails if parent directories are missing

Simple use case: os.mkdir('new_folder')

os.makedirs()

Creates all intermediate directories in the path

Does not fail if parents are missing — it creates them

Useful for nested paths: os.makedirs('parent/child')

os.remove()

Deletes a single file only

Raises an error if used on a directory

Commonly used for cleaning up individual files

os.rmdir()

Deletes a single empty directory only

Raises an error if the directory contains files

Must manually empty directory first or use shutil.rmtree

Absolute path

Starts from the root of the file system (e.g., / or C:\)

Always points to the exact same location regardless of cwd

Safer for scripts that must run from any directory

Relative path

Starts from the current working directory (e.g., ./data or data)

Changes meaning if the cwd changes

More portable but requires cwd to be correct

Watch Out for These

Mistake

The os module and pathlib module are completely interchangeable and do exactly the same things in the same way.

Correct

While both modules handle file system operations, os uses string-based paths and function calls, while pathlib uses object-oriented Path objects. pathlib is generally cleaner and more Pythonic, but os is still widely used in older codebases.

Beginners see that both modules can check if a file exists and assume they're identical, not realising the different programming styles and subtleties in how they handle paths.

Mistake

os.remove() can delete both files and directories.

Correct

os.remove() only deletes files. To delete a directory (an empty one), you must use os.rmdir(). If the directory contains files, you need shutil.rmtree() or manually empty it first.

The word 'remove' sounds general, so beginners assume it works for anything. The operating system treats files and directories differently, and Python reflects that.

Mistake

You can use os.mkdir() to create nested directories like os.makedirs().

Correct

os.mkdir() only creates a single directory and raises a FileNotFoundError if any parent in the path doesn't exist. os.makedirs() creates all intermediate directories. In pathlib, you need to pass parents=True to Path.mkdir() to achieve the same effect.

Beginner tutorials often show mkdir for a single folder. When they try to create a nested path, they expect it to 'just work', not realising the distinction.

Mistake

Paths in Python are always strings, so you can just concatenate them like 'folder/' + 'file.txt'.

Correct

While that works on some systems, it's not cross-platform. Windows uses backslashes, so you'd get 'folder\file.txt'. Always use os.path.join() or pathlib Path / operator for safe path building.

Most beginners start on Windows or Mac, and simple concatenation seems to work. When they share code or work on a different OS, it breaks. They don't know about path separators.

Mistake

The current working directory never changes within a running Python script unless you explicitly change it.

Correct

That's true, but many beginners forget that operations like file open() with a relative path depend on the cwd. If another part of the code calls os.chdir(), earlier assumptions about relative paths become invalid. Also, the cwd might be different when running from an IDE vs the terminal.

They treat the cwd as a fixed constant, not a variable that can change during execution. They don't debug by printing os.getcwd() to confirm where files are being read from.

Do You Actually Know This?

Reveal each answer, then mark whether you got it right. Score 60%+ to unlock the next chapter.

Frequently Asked Questions

What is the difference between os.path.exists and os.path.isfile?

os.path.exists returns True if the path exists as either a file or a directory. os.path.isfile returns True only if the path exists and is a regular file (not a directory). So if a path points to a folder, exists returns True but isfile returns False.

Why does os.mkdir fail with 'No such file or directory' when I try to create a nested folder?

os.mkdir only creates a single directory. If any parent directory in the path doesn't exist, it fails. Use os.makedirs instead, which creates all missing intermediate directories automatically.

Should I use os or pathlib in my Python project?

pathlib is generally preferred in modern Python code (3.6+) because it's cleaner, more Pythonic, and automatically handles cross-platform path separators. However, the PCAP exam tests both, and you may encounter os in older codebases.

How do I get the current working directory in Python?

Use os.getcwd() (get current working directory) to return a string. With pathlib, use Path.cwd() to get a Path object representing the current directory.

What does os.path.join do and why should I use it?

os.path.join takes multiple path segments and joins them into a single path using the correct separator for your operating system. For example, os.path.join('folder', 'subfolder', 'file.txt') returns 'folder/subfolder/file.txt' on Linux/Mac and 'folder\\subfolder\\file.txt' on Windows. This prevents bugs when your code runs on different systems.

How do I delete a directory that still has files inside it?

You cannot delete a non-empty directory with os.rmdir (it only works on empty directories). Use shutil.rmtree('path_to_directory') which recursively deletes the directory and all its contents. Be very careful with this command — it permanently deletes everything with no undo.

Terms Worth Knowing

Keep going

You've finished Working with the File System and Directories. Continue through the PCAP-31-03 study guide to build a complete picture of the exam.

Done with this chapter?