Как получить список файлов в директории на C++? (кросс-платформенно)
Современное решение: std::filesystem (C++17)
Начиная с C++17, стандартная библиотека предоставляет модуль std::filesystem, который решает вашу проблему кросс-платформенно и без танцев с бубном. Это единственный правильный способ для нового кода. Он работает на Windows, Linux, macOS и других POSIX-системах.
Вот полный рабочий пример, который делает именно то, что вы просите:
#include <iostream>
#include <vector>
#include <string>
#include <filesystem>
namespace fs = std::filesystem;
std::vector<std::string> getFilesInDirectory(const std::string& path) {
std::vector<std::string> files;
try {
// Проверяем, существует ли путь и является ли он директорией
if (!fs::exists(path) || !fs::is_directory(path)) {
std::cerr << "Ошибка: путь не существует или не является директорией: " << path << std::endl;
return files; // возвращаем пустой вектор
}
// Итерация по содержимому директории
for (const auto& entry : fs::directory_iterator(path)) {
// Проверяем, что это обычный файл (не директория, не симлинк и т.д.)
if (entry.is_regular_file()) {
// Добавляем имя файла (можно также полный путь: entry.path().string())
files.push_back(entry.path().filename().string());
}
}
} catch (const fs::filesystem_error& e) {
std::cerr << "Ошибка файловой системы: " << e.what() << std::endl;
} catch (const std::exception& e) {
std::cerr << "Общая ошибка: " << e.what() << std::endl;
}
return files;
}
int main() {
auto files = getFilesInDirectory("C:\\MyFolder"); // или "/home/user/MyFolder" на Linux
for (const auto& f : files) {
std::cout << f << std::endl;
}
return 0;
}
Ключевые моменты:
- Проверка существования и типа:
fs::exists(path)иfs::is_directory(path)— обязательны, чтобы избежать исключений. - Итерация:
fs::directory_iteratorавтоматически игнорирует "." и ".." — это встроенное поведение. - Фильтрация файлов:
entry.is_regular_file()отсеивает папки и специальные файлы. - Обработка ошибок: Используйте try-catch, так как операции с файловой системой могут кидать исключения (например, нет прав доступа).
- Кросс-платформенность: Код одинаково работает на Windows (с обратными слешами) и Linux (с прямыми).
Фильтрация по расширению (например, только .txt):
Добавьте проверку расширения внутри цикла:
if (entry.is_regular_file() && entry.path().extension() == ".txt") {
files.push_back(entry.path().filename().string());
}
Альтернатива: рекурсивный обход поддиректорий:
Если вам нужно собрать файлы из всех подпапок, замените directory_iterator на recursive_directory_iterator:
for (const auto& entry : fs::recursive_directory_iterator(path)) {
// ... та же логика
}
Важно: Убедитесь, что ваш компилятор поддерживает C++17. В Visual Studio 2022 это включено по умолчанию. Для GCC/MinGW добавьте флаг -std=c++17 и линкуйтесь с -lstdc++fs (на старых версиях) или просто -std=c++17 (на новых).
Этот подход — самый современный, безопасный и рекомендуемый. Забудьте про WinAPI и dirent.h, если только вы не пишете код для очень старых компиляторов.
<<Классический подход: dirent.h (для C++11/14 или embedded)
Если по каким-то причинам вы не можете использовать C++17 (например, проект на древнем компиляторе или микроконтроллере), то можно использовать POSIX-совместимую библиотеку dirent.h. Она работает на Linux и macOS "из коробки", а на Windows её можно эмулировать (есть порт dirent для Windows).
#include <iostream>
#include <vector>
#include <string>
#include <dirent.h> // POSIX
std::vector<std::string> getFilesInDirectory(const std::string& path) {
std::vector<std::string> files;
DIR* dir = opendir(path.c_str());
if (!dir) {
std::cerr << "Не удалось открыть директорию: " << path << std::endl;
return files;
}
struct dirent* entry;
while ((entry = readdir(dir)) != nullptr) {
std::string name = entry->d_name;
// Игнорируем "." и ".."
if (name == "." || name == "..") continue;
// На POSIX системах можно проверить тип файла через entry->d_type
// Но это не обязательно: просто собираем всё, кроме "." и ".."
// Для фильтрации только файлов нужно делать stat()
files.push_back(name);
}
closedir(dir);
return files;
}
Недостатки:
- Не кросс-платформенно "из коробки" (на Windows нужна отдельная библиотека).
- Нет встроенной фильтрации "только файлы" — нужно делать дополнительный вызов
stat()для каждого элемента. - Ручное управление памятью (закрытие дескриптора).
- Небезопасно для многопоточности (если не использовать реентерабельные версии).
Этот метод — наследие прошлого. Используйте его только если std::filesystem недоступен. Для нового кода всегда выбирайте C++17.