Как получить список файлов в папке на Python

Как получить список файлов в папке на Python Полезное

Список файлов в папке — это перечень имен (или полных путей) файлов и вложенных папок, который программа получает от операционной системы. В Python это делается стандартной библиотекой, без сторонних пакетов: модулем os или более удобным pathlib. Ниже — как получить такой список, как отделить файлы от папок, отфильтровать по расширению и обойти вложенные каталоги рекурсивно. Все примеры запущены, вывод под каждым — реальный.

Какой инструмент выбрать

В стандартной библиотеке есть три основных способа. Начинать проще с pathlib — это современный и читаемый вариант, рекомендованный для нового кода.

Инструмент Что делает Когда брать
os.listdir(path) список имен внутри папки (строки) быстрый разовый список имен
os.scandir(path) элементы с готовым типом (файл/папка) без лишних запросов к диску много файлов, важна скорость
pathlib.Path объектный путь: iterdir, glob, rglob новый код, фильтры, рекурсия

Дальше разберем каждый способ на одной и той же тестовой папке.

os.listdir: самый короткий способ

os.listdir(path) возвращает список имен всех элементов папки — и файлов, и вложенных папок вперемешку, без пути к ним. Это отправная точка, дальше имена обычно фильтруют.

Первые строки примера создают тестовую папку example с тремя файлами и одной вложенной папкой — в реальной задаче вместо этого укажите свой путь в переменной folder. Сортировка нужна лишь для стабильного вывода: сам порядок в listdir зависит от файловой системы и не гарантирован.

import os

# готовим тестовую папку (в своей задаче укажите нужный путь)
os.makedirs("example/sub", exist_ok=True)
for name in ["report.txt", "notes.md", "data.csv"]:
    open(os.path.join("example", name), "w").close()
open("example/sub/inner.txt", "w").close()

folder = "example"

# все имена: файлы и папки вперемешку
print("listdir:", sorted(os.listdir(folder)))

# только файлы
files = [n for n in os.listdir(folder) if os.path.isfile(os.path.join(folder, n))]
print("только файлы:", sorted(files))

# только папки
dirs = [n for n in os.listdir(folder) if os.path.isdir(os.path.join(folder, n))]
print("только папки:", sorted(dirs))

Вывод программы:

listdir: ['data.csv', 'notes.md', 'report.txt', 'sub']
только файлы: ['data.csv', 'notes.md', 'report.txt']
только папки: ['sub']

Важная деталь: listdir отдает только имена, без пути. Чтобы проверить тип элемента через os.path.isfile, имя нужно склеить с папкой через os.path.join, иначе проверка пойдет относительно текущего каталога и вернет неверный результат.

os.scandir: то же, но быстрее

os.scandir(path) возвращает не строки, а объекты DirEntry, у которых уже есть методы is_file() и is_dir(). Ключевое отличие от связки listdir + os.path.isfile: тип элемента scandir берет из данных, которые ОС отдает при чтении папки, и не делает отдельный запрос к диску на каждый файл. На больших папках это заметно быстрее.

scandir возвращает итератор, который держит папку открытой, поэтому его используют через with — так дескриптор закроется сам.

import os

os.makedirs("example/sub", exist_ok=True)
for name in ["report.txt", "notes.md", "data.csv"]:
    open(os.path.join("example", name), "w").close()
open("example/sub/inner.txt", "w").close()

with os.scandir("example") as it:
    for entry in sorted(it, key=lambda e: e.name):
        kind = "папка" if entry.is_dir() else "файл"
        print(f"{entry.name:12} - {kind}  (путь: {entry.path})")

Вывод программы:

data.csv     - файл  (путь: example/data.csv)
notes.md     - файл  (путь: example/notes.md)
report.txt   - файл  (путь: example/report.txt)
sub          - папка  (путь: example/sub)

У DirEntry есть удобное поле entry.path — готовый путь вида example/report.txt, его не надо собирать вручную через os.path.join.

pathlib: современный и читаемый вариант

Модуль pathlib появился в Python 3.4 и с тех пор считается предпочтительным для работы с путями. Путь становится объектом Path, а операции над ним — методами. Список содержимого папки дает Path.iterdir(), а фильтр по шаблону — Path.glob().

from pathlib import Path

folder = Path("example")
(folder / "sub").mkdir(parents=True, exist_ok=True)
for name in ["report.txt", "notes.md", "data.csv"]:
    (folder / name).touch()
(folder / "sub" / "inner.txt").touch()

# все элементы папки (объекты Path)
print("iterdir:", sorted(p.name for p in folder.iterdir()))

# только файлы, полными путями
print("файлы:", sorted(str(p) for p in folder.iterdir() if p.is_file()))

# фильтр по расширению шаблоном
print("glob *.txt:", sorted(p.name for p in folder.glob("*.txt")))

Вывод программы:

iterdir: ['data.csv', 'notes.md', 'report.txt', 'sub']
файлы: ['example/data.csv', 'example/notes.md', 'example/report.txt']
glob *.txt: ['report.txt']

Оператор / собирает путь из частей независимо от ОС: folder / "sub" / "inner.txt" даст корректный разделитель и в Windows, и в Linux. У каждого Path сразу есть p.name (имя), p.suffix (расширение с точкой), p.stem (имя без расширения) — это удобнее ручного разбора строки.

Фильтр по расширению

Отобрать файлы одного типа можно двумя путями. Через glob — шаблоном *.txt. Через iterdir — сравнив поле p.suffix; так удобно собрать сразу несколько расширений в одном условии.

from pathlib import Path

folder = Path("example")
folder.mkdir(exist_ok=True)
for name in ["report.txt", "notes.md", "data.csv", "photo.jpg"]:
    (folder / name).touch()

# один тип - шаблоном
print("txt:", sorted(p.name for p in folder.glob("*.txt")))

# несколько типов - по suffix
wanted = {".txt", ".md"}
docs = [p.name for p in folder.iterdir() if p.suffix in wanted]
print("txt и md:", sorted(docs))

Вывод программы:

txt: ['report.txt']
txt и md: ['notes.md', 'report.txt']

Оговорка про регистр: p.suffix возвращает расширение как есть, поэтому файл PHOTO.JPG не совпадет с .jpg. Если нужен нечувствительный к регистру фильтр, приводите расширение к нижнему: p.suffix.lower().

Рекурсивный обход вложенных папок

Если файлы разложены по подпапкам, нужен рекурсивный обход. Два рабочих инструмента: os.walk из модуля os и метод Path.rglob из pathlib.

os.walk на каждом шаге выдает тройку: текущая папка, список ее подпапок и список ее файлов — и сам спускается во вложенные каталоги. rglob("*.txt") короче, когда нужны только файлы по маске из всего дерева.

import os
from pathlib import Path

folder = Path("example")
(folder / "sub").mkdir(parents=True, exist_ok=True)
for name in ["report.txt", "notes.md", "data.csv"]:
    (folder / name).touch()
(folder / "sub" / "inner.txt").touch()

# os.walk - обходит папку и все вложенные
print("os.walk:")
for root, dirs, files in os.walk("example"):
    for f in sorted(files):
        print("  ", os.path.join(root, f))

# pathlib: все .txt рекурсивно, включая подпапки
print("rglob *.txt:", sorted(str(p) for p in folder.rglob("*.txt")))

Вывод программы:

os.walk:
   example/data.csv
   example/notes.md
   example/report.txt
   example/sub/inner.txt
rglob *.txt: ['example/report.txt', 'example/sub/inner.txt']

Одно предупреждение по производительности: не собирайте все дерево в один большой список через list(Path(...).rglob("*")) на огромных каталогах — это займет память. И os.walk, и rglob — генераторы, обрабатывайте элементы по одному в цикле.

Обработка ошибок доступа

Если к папке нет прав или ее нет, вызовы упадут с исключением: FileNotFoundError для отсутствующего пути, PermissionError для закрытого. Отдельная тонкость есть у os.walk: по умолчанию он молча пропускает папки, в которые не смог зайти, и не сообщает об этом. Чтобы узнавать о таких случаях, передают обработчик через параметр onerror.

import os

try:
    names = os.listdir("no_such_folder")
except FileNotFoundError:
    print("папки нет")
except PermissionError:
    print("нет доступа к папке")
else:
    print(names)

Вывод программы:

папки нет

Такой каркас с try/except полезен в любом скрипте, который перебирает чужие каталоги: он не даст программе аварийно завершиться на первой же недоступной папке.

Выводы

  • Список файлов в папке в Python дает стандартная библиотека без сторонних пакетов: os.listdir, os.scandir или pathlib.
  • Для нового кода берите pathlib: iterdir для содержимого, glob/rglob для фильтра и рекурсии, удобные поля name, suffix, stem.
  • os.scandir быстрее связки listdir + os.path.isfile, потому что тип файла берется из чтения папки, а не отдельным запросом к диску.
  • Рекурсивный обход — это os.walk или rglob; оба генераторы, не материализуйте их в большой список на огромных деревьях.
  • Отсутствующая или закрытая папка бросает FileNotFoundError/PermissionError, а os.walk по умолчанию тихо пропускает недоступные каталоги — ловите это через try/except и onerror.

Где применяется и что учить дальше

Получение списка файлов — базовая операция почти в любом скрипте автоматизации: массовое переименование и сортировка загрузок, сбор логов, пакетная обработка изображений или таблиц, резервное копирование, поиск дубликатов. Это одна из первых практических задач, на которой новичок переходит от синтаксиса к реальной пользе от Python.

Освойте тему на практике

Если хочется освоить Python с нуля и системно — от синтаксиса и работы с файлами до первых рабочих скриптов, посмотрите курс Python Basic. Оценить формат и уровень до старта помогают бесплатные открытые уроки Otus — живые занятия с преподавателями.

FAQ

Чем os.listdir отличается от os.walk? os.listdir смотрит только внутрь одной папки и отдает имена. os.walk спускается во все вложенные подпапки и на каждом уровне отдает отдельно список папок и список файлов.

Как получить список файлов по маске, например только *.py? Шаблоном: Path("folder").glob("*.py") для одной папки или rglob("*.py") для поиска во всех вложенных. Оба возвращают объекты Path, у которых готов и путь, и имя.

Почему os.listdir возвращает имена в непонятном порядке? Порядок зависит от файловой системы и не гарантирован. Если нужен предсказуемый порядок, сортируйте результат сами — например, sorted(os.listdir(path)) по имени.

OTUS Журнал
Скидка 5% 14-20 сентября на курсы (popup)