Зачем вам может понадобиться список файлов в 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. Он мощный, но код получается многословным.
Как это работает
- Вызываете
FindFirstFileс шаблоном (например,"C:\\*"). - Получаете хендл и первую запись.
- В цикле вызываете
FindNextFile, пока не вернется 0. - Закрываете хендл через
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; }Блоги
Рекомендаций по книгам
Читайте также