For each file in directory Python – a practical guide to iterating over files with clean, reliable code
When you need to process a collection of files—whether to rename images, parse logs, or batch‑convert data—the first step is to walk through a directory and handle each entry individually. Plus, python offers several built‑in ways to achieve this, each suited to different scenarios. This article shows you how to loop over files in a directory using the standard library, explains the underlying mechanics, highlights performance considerations, and provides ready‑to‑copy snippets you can adapt to your own projects.
Table of Contents
-
- 2.1. Using
os.listdir - 2.2. Leveraging
pathlib.Path - 2.3. Applying
globandrglob - 2.4. Walking directories with
os.walk
- 2.1. Using
<a name="introduction"></a>
Introduction
The phrase for each file in directory Python captures a frequent programming task: iterate over every file (and optionally sub‑directories) inside a given folder and apply some operation. Whether you are a beginner automating file cleanup or a data scientist preprocessing thousands of CSV files, mastering directory traversal makes your scripts more dependable and portable.
In the sections below we’ll examine four primary techniques, discuss when each shines, and show concrete code examples that you can run immediately. All snippets assume Python 3.8+ and rely only on the standard library—no external dependencies required.
<a name="core-techniques"></a>
Core Techniques for Listing Files
Below are the most idiomatic ways to obtain a list of files in a directory. Each method returns an iterable you can feed directly into a for loop.
2.1. Using os.listdir
import os
directory = "/path/to/your/folder"
for entry in os.listdir(directory):
full_path = os.path.join(directory, entry)
if os.path.
**How it works**
- `os.listdir(directory)` returns a plain Python list of *names* (strings) contained in `directory`.
- Because the function yields only names, you must reconstruct the absolute or relative path with `os.path.join`.
- The call is **eager**: the entire list is built in memory before the loop starts. For very large directories this can consume noticeable RAM, but for most everyday workloads it is negligible.
### 2.2. Leveraging `pathlib.Path`
```python
from pathlib import Path
directory = Path("/path/to/your/folder")
for file_path in directory.iterdir():
if file_path.is_file(): # filter out directories
print(file_path) # your processing goes here
How it works
Path.iterdir()is a generator that yieldsPathobjects one at a time, keeping memory usage low.Pathobjects provide a rich, object‑oriented API (is_file(),suffix,stem, etc.) that often leads to more readable code than string manipulation.- Since Python 3.5,
pathlibis the recommended way to handle filesystem paths in a cross‑platform manner.
2.3. Applying glob and rglob
from pathlib import Path
directory = Path("/path/to/your/folder")
# Non‑recursive match: only files directly inside the directory
for file_path in directory.glob("*"):
if file_path.is_file():
print(file_path)
# Recursive match: includes files in all sub‑directories
for file_path in directory.rglob("*"):
if file_path.is_file():
print(file_path)
How it works
glob(pattern)uses Unix‑style wildcards (*,?,[seq]) to filter entries as they are yielded.rglobperforms a recursive walk, equivalent toos.walkbut returningPathobjects.- This approach shines when you need to filter by extension or name pattern while iterating, eliminating an extra
ifstatement.
2.4. Walking directories with os.walk
import os
root_dir = "/path/to/your/folder"
for dirpath, dirnames, filenames in os.On top of that, walk(root_dir):
for fname in filenames:
full_path = os. path.
**How it works**
- `os.walk` generates a triple `(dirpath, dirnames, filenames)` for each directory it visits, starting at `root_dir`.
- It is inherently recursive; you can control depth by modifying the `dirnames` list in‑place (e.g., `dirnames.clear()` to stop descending).
- Ideal when you need to process files *and* retain information about their containing directory (e.g., preserving relative paths).
---
## Choosing the Right Approach
| Scenario | Recommended Technique | Why |
|----------|----------------------|-----|
| Simple list of files in a single folder, no filtering | `os.listdir` or `Path.iterdir` | Minimal overhead, straightforward |
| Need to filter by extension or name pattern (e.g., `*.txt`) | `Path.glob("*.That said, txt")` | Pattern matching built‑in, no extra `if` |
| Want recursive traversal with filtering | `Path. That's why rglob("*. txt")` | Combines recursion and globbing |
| Require full directory tree information (e.Practically speaking, g. , preserve relative paths) | `os.walk` | Gives you `dirpath` alongside filenames |
| Memory‑critical environment with huge directories | `Path.iterdir` or `os.
> **Note:** For even better performance on large directories, consider `os.scandir`, which returns `Dirent` objects that cache file type information, reducing extra system calls. The usage pattern mirrors `os.listdir` but is often faster.
---
## Error Handling and Safety Tips
File system operations can fail for many reasons—missing permissions, broken symlinks, or race conditions where a file disappears between listing and processing. Wrap your loop in a `try/except` block and validate each path before use.
```python
from pathlib import Path
def process_file(p: Path) -> None:
# Placeholder for real work
print(f"Processing {p}")
directory = Path("/risky/folder")
for entry in directory.iterdir():
try:
```python
from pathlib import Path
def process_file(p: Path) -> None:
# Placeholder for real work
print(f"Processing {p}")
directory = Path("/risky/folder")
for entry in directory.iterdir():
try:
# Skip broken symlinks and non‑regular files if desired
if entry.is_symlink() and not entry.exists():
continue
if entry.Plus, is_file():
process_file(entry)
except PermissionError:
print(f"⚠️ Permission denied: {entry}")
except FileNotFoundError:
# The file vanished between the iterator and the check
print(f"🔎 File disappeared: {entry}")
except OSError as exc:
# Catch‑all for other OS‑related issues (e. g.
### Putting It All Together
When you combine a generator‑based iterator with defensive error handling, you get a loop that is both **memory‑efficient** and **dependable** in the face of an unpredictable filesystem. The pattern above works for any of the traversal methods discussed earlier—just replace `directory.iterdir()` with `directory.Also, glob("*. txt")`, `directory.rglob("*.log")`, or the triple‑yield from `os.walk` as needed.
#### Quick checklist for production‑grade file walks
| ✅ Item | Why it matters |
|--------|----------------|
| **Use generators** (`iterdir`, `glob`, `rglob`, `os.scandir`) | Keeps memory footprint low even with millions of entries. |
| **Prefer `Path` objects** | Automatic OS‑specific path handling and rich methods (`is_file`, `exists`, `resolve`). |
| **Filter early** (`glob("*.Now, csv")`) | Reduces work and eliminates extra `if` statements. |
| **Handle transient errors** (`FileNotFoundError`, `PermissionError`) | Prevents crashes when files disappear or access changes mid‑iteration. |
| **Guard against broken symlinks** | Avoids following dangling links that could raise exceptions or lead to security issues. |
| **Log or collect failures** | Enables post‑run analysis without halting the whole process.
### Conclusion
Choosing the right directory‑walking technique hinges on three factors: **scope** (single folder vs. Think about it: recursive tree), **filtering needs** (plain list vs. pattern‑based), and **information required** (just filenames vs. full directory context). Consider this: for quick, non‑recursive listings, `Path. iterdir` or `os.listdir` are the lightest options. When you need to match extensions or glob patterns while iterating, `Path.glob` and its recursive sibling `Path.rglob` embed the filter directly, saving you an extra conditional check. If you must preserve hierarchical information—such as building relative paths or performing per‑directory actions—`os.walk` (or its `scandir` counterpart) gives you the `dirpath`, `dirnames`, and `filenames` tuple at each step.
Quick note before moving on.
Regardless of the method you select, always wrap the per‑file logic in a `try/except` block that catches the most common filesystem exceptions (`PermissionError`, `FileNotFoundError`, and a generic `OSError`). This defensive stance ensures your script remains stable even when the underlying storage is volatile, permissions shift, or files are removed between the listing and the processing stage.
By matching the traversal tool to your task’s specifics and layering in prudent error handling, you’ll write file‑walking code that is both **efficient** and **resilient**—ready for anything from modest scripts to large‑scale data‑pipeline workloads. Happy walking!