Получаем список файлов в папке на C++: полный гайд от новичка до профи

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Зачем вам может понадобиться список файлов в C++?

Представьте: вы пишете программу, которая должна обработать сотни логов, проверить наличие конфигурационных файлов или просто показать пользователю, что лежит в папке. Без умения «заглянуть» внутрь директории вы упираетесь в стену. Именно поэтому вопрос «How can I get the list of files in a directory using C or C++?» — один из самых популярных на Stack Overflow. И сегодня мы разберем его от и до.

В статье я покажу три основных способа: от классического C-стиля (работает везде, но требует аккуратности) до современного C++17 std::filesystem (лаконично, безопасно и красиво). Вы узнаете, как выбрать правильный инструмент под свою задачу, и получите готовые примеры кода, которые можно сразу вставить в свой проект.

Способ 1: Классика — dirent.h (POSIX / Linux / macOS)

Этот метод — «дедушка» всех решений. Он используется в C и C++ на Unix-подобных системах. Суть проста: открываете директорию, читаете записи по одной, закрываете. Никаких наворотов, зато полный контроль.

Подключение и структуры

Вам понадобятся:

  • #include <dirent.h> — работа с директориями
  • DIR *dir — указатель на поток директории
  • struct dirent *entry — структура, содержащая имя файла

Пример кода: простой вывод всех имен

#include <iostream>
#include <dirent.h>

int main() {
    const char* path = "."; // текущая папка
    DIR* dir = opendir(path);
    if (dir == nullptr) {
        std::cerr << "Не удалось открыть директорию: " << path << std::endl;
        return 1;
    }

    struct dirent* entry;
    while ((entry = readdir(dir)) != nullptr) {
        std::cout << entry->d_name << std::endl;
    }

    closedir(dir);
    return 0;
}

Важные нюансы

  • Функция readdir() возвращает имена . (текущая директория) и .. (родительская). Обычно их нужно пропускать:
if (entry->d_name[0] == '.') continue;
  • Этот код **не работает на Windows** из коробки. Для Windows есть windows.h и FindFirstFile/FindNextFile (о нем позже).
  • Плюсы: минимализм, работа без C++17. Минусы: не кроссплатформенно, нет фильтрации по типу файла.

Способ 2: Windows API — FindFirstFile и FindNextFile

Если ваша цель — Windows, забудьте про dirent.h. Вместо этого используйте родной WinAPI. Он мощный, но код получается многословным.

Как это работает

  1. Вызываете FindFirstFile с шаблоном (например, "C:\\*").
  2. Получаете хендл и первую запись.
  3. В цикле вызываете FindNextFile, пока не вернется 0.
  4. Закрываете хендл через FindClose.

Пример: список файлов в корне диска C:

#include <iostream>
#include <windows.h>

int main() {
    WIN32_FIND_DATA findFileData;
    HANDLE hFind = FindFirstFile("C:\\*", &findFileData);

    if (hFind == INVALID_HANDLE_VALUE) {
        std::cerr << "Не удалось найти файлы (код ошибки: " << GetLastError() << ")" << std::endl;
        return 1;
    }

    do {
        // Пропускаем "." и ".."
        if (strcmp(findFileData.cFileName, ".") != 0 && strcmp(findFileData.cFileName, "..") != 0) {
            std::cout << findFileData.cFileName << std::endl;
        }
    } while (FindNextFile(hFind, &findFileData) != 0);

    FindClose(hFind);
    return 0;
}

Что важно знать

  • В WIN32_FIND_DATA есть поле dwFileAttributes, по которому можно отличить файл от папки (FILE_ATTRIBUTE_DIRECTORY).
  • Этот код **не кроссплатформенный**. Переносить на Linux будет больно.
  • Плюсы: полный контроль, доступ к атрибутам. Минусы: громоздкость, привязанность к Windows.

Способ 3: Современный C++17 — std::filesystem (кроссплатформенный рай)

Начиная с C++17, в стандартной библиотеке появился модуль std::filesystem. Это именно то, о чем мечтали разработчики: единый API для Linux, macOS и Windows. Никаких #ifdef, никаких танцев с бубном.

Подключение

#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;

Пример 1: Просто список всех файлов и папок

#include <iostream>
#include <filesystem>

namespace fs = std::filesystem;

int main() {
    std::string path = ".";

    for (const auto& entry : fs::directory_iterator(path)) {
        std::cout << entry.path().filename() << std::endl;
    }
    return 0;
}

Пример 2: Только файлы (без папок)

#include <iostream>
#include <filesystem>

namespace fs = std::filesystem;

int main() {
    std::string path = ".";

    for (const auto& entry : fs::directory_iterator(path)) {
        if (entry.is_regular_file()) { // проверяем, что это файл, а не папка
            std::cout << entry.path().filename() << std::endl;
        }
    }
    return 0;
}

Пример 3: Рекурсивный обход всех подпапок

Замените directory_iterator на recursive_directory_iterator — и готово:

#include <iostream>
#include <filesystem>

namespace fs = std::filesystem;

int main() {
    std::string path = ".";

    for (const auto& entry : fs::recursive_directory_iterator(path)) {
        if (entry.is_regular_file()) {
            std::cout << entry.path() << std::endl; // полный путь
        }
    }
    return 0;
}

                
                

Блоги

Рекомендаций по книгам