Как получить список файлов в директории в Rust?
Использование std::fs::read_dir с обработкой ошибок
Ваш подход в целом правильный, но требует доработки для идиоматичного Rust. read_dir возвращает итератор, каждый элемент которого — это Result. Чтобы получить только имена файлов, нужно обработать каждый результат, извлечь имя и отфильтровать директории.
use std::fs;
use std::path::Path;
fn list_files(dir: &Path) -> std::io::Result<Vec<String>> {
let mut files = Vec::new();
for entry in fs::read_dir(dir)? {
let entry = entry?; // Обрабатываем ошибку доступа к элементу
let path = entry.path();
// Проверяем, что это файл (не директория)
if path.is_file() {
if let Some(name) = path.file_name() {
if let Some(name_str) = name.to_str() {
files.push(name_str.to_string());
}
}
}
}
Ok(files)
}
fn main() {
match list_files(Path::new(".")) {
Ok(files) => {
for file in files {
println!("{}", file);
}
}
Err(e) => eprintln!("Ошибка: {}", e),
}
}
Ключевые моменты:
- Обработка ошибок: Используйте оператор
?для проброса ошибок вместоunwrap(). Это позволяет вызывающему коду решать, что делать с ошибкой. - Извлечение имени:
entry.path()возвращает полный путь,file_name()— последний компонент (имя файла).to_str()конвертируетOsStrв&str. - Фильтрация:
path.is_file()проверяет, что это обычный файл, а не директория или симлинк. - Безопасность: Используйте
if let Some(...)для обработки случаев, когда имя файла не является валидным UTF-8.
Более краткая версия с filter_map:
use std::fs;
use std::path::Path;
fn list_files_compact(dir: &Path) -> std::io::Result<Vec<String>> {
let entries = fs::read_dir(dir)?;
Ok(entries
.filter_map(|entry| entry.ok()) // Игнорируем ошибки доступа
.filter(|entry| entry.path().is_file())
.filter_map(|entry| {
entry.path()
.file_name()?
.to_str()
.map(|s| s.to_string())
})
.collect())
}
Этот вариант использует цепочку итераторов: filter_map отбрасывает ошибки и None-значения, filter оставляет только файлы. Результат собирается в Vec<String>.
Рекомендации:
- Всегда обрабатывайте ошибки — файловая система непредсказуема (нет прав доступа, неверный путь и т.д.).
- Используйте
PathиPathBufдля работы с путями — они кроссплатформенны. - Для рекурсивного обхода директорий рассмотрите крейт
walkdir.
Использование крейта walkdir для рекурсивного обхода
Если вам нужно не только получить список файлов в одной директории, но и обойти все вложенные папки, стандартная библиотека Rust становится неудобной. В этом случае лучшим решением будет крейт walkdir.
Добавьте в Cargo.toml:
[dependencies]
walkdir = "2"
Пример кода для рекурсивного поиска всех файлов:
use walkdir::WalkDir;
fn main() {
for entry in WalkDir::new(".")
.into_iter()
.filter_map(|e| e.ok()) // Игнорируем ошибки
.filter(|e| e.file_type().is_file()) // Только файлы
{
println!("{}", entry.path().display());
}
}
Преимущества walkdir:
- Автоматически обрабатывает вложенные директории.
- Позволяет настроить глубину обхода (
.max_depth(2)). - Игнорирует скрытые файлы и символические ссылки при необходимости.
- Более читаемый код для сложных сценариев (например, поиск файлов по расширению).
Для простого случая (только текущая директория) стандартная библиотека достаточна, но для реальных проектов я рекомендую walkdir — он экономит время и уменьшает количество boilerplate-кода.
Ответов пока нет.
Войдите чтобы оставить ответ