Работа с файловой системой в Rust: полное руководство для начинающих

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

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

Начать курс

Введение в работу с файловой системой в Rust

Rust — современный системный язык программирования, который уделяет огромное внимание безопасности, производительности и контролю над памятью. Работа с файловой системой — одна из фундаментальных задач, с которой сталкивается каждый разработчик. В этой статье мы подробно разберем, как читать и записывать файлы, создавать директории, обрабатывать ошибки и использовать стандартную библиотеку std::fs для эффективного взаимодействия с файловой системой.

Мы начнем с самых основ и постепенно перейдем к более сложным сценариям. Все примеры кода написаны на Rust и готовы к запуску. Если вы только начинаете изучать Rust, эта статья станет отличной отправной точкой для освоения ввода-вывода (I/O) в этом языке.

Основные модули и типы для работы с файловой системой

В Rust вся функциональность для работы с файлами и директориями сосредоточена в модуле std::fs. Кроме того, важную роль играют типы Path и PathBuf из модуля std::path, которые представляют пути к файлам и директориям.

Типы Path и PathBuf

Path — это слайс (срез) для работы с путями без владения данными. PathBuf — это владеющая версия, которую можно изменять. Они предоставляют удобные методы для манипуляции путями.

use std::path::Path;
use std::path::PathBuf;

fn main() {
    // Создание PathBuf
    let mut path = PathBuf::from("/tmp");
    path.push("example.txt");
    println!("Путь: {}", path.display());

    // Преобразование в Path
    let path_ref: &Path = path.as_path();
    println!("Родительская директория: {:?}", path_ref.parent());
}

Модуль std::fs

Модуль std::fs содержит основные функции для работы с файловой системой. Вот наиболее часто используемые:

  • read_to_string — чтение файла в строку
  • write — запись данных в файл
  • create_dir и create_dir_all — создание директорий
  • remove_file и remove_dir — удаление файлов и директорий
  • metadata — получение информации о файле
  • copy и rename — копирование и переименование

Чтение и запись файлов в Rust

Самый простой способ прочитать или записать файл — использовать функции-обертки, которые выполняют всю работу за один вызов. Они подходят для небольших файлов, которые целиком помещаются в память.

Чтение файла целиком

use std::fs;

fn main() -> Result<(), std::io::Error> {
    let content = fs::read_to_string("hello.txt")?;
    println!("Содержимое файла:\n{}", content);
    Ok(())
}

Функция read_to_string возвращает Result<String>. Если файл не существует или нет прав на чтение, будет возвращена ошибка. Обратите внимание на оператор ? — он автоматически пробрасывает ошибку наверх.

Запись в файл

use std::fs;

fn main() -> Result<(), std::io::Error> {
    let data = "Привет, Rust!";
    fs::write("output.txt", data)?;
    println!("Файл записан успешно");
    Ok(())
}

Функция write перезаписывает файл, если он существует, или создает новый. Для добавления данных в конец файла используйте OpenOptions.

Работа с бинарными файлами

Для чтения и записи бинарных данных используйте read и write с вектором байтов:

use std::fs;

fn main() -> Result<(), std::io::Error> {
    // Запись бинарных данных
    let bytes: Vec<u8> = vec![0, 1, 2, 3, 255];
    fs::write("binary.dat", &bytes)?;

    // Чтение как байты
    let read_bytes = fs::read("binary.dat")?;
    println!("Прочитано байт: {}", read_bytes.len());
    Ok(())
}

Работа с директориями и навигация по файловой системе

Rust предоставляет удобные инструменты для создания, удаления и обхода директорий.

Создание и удаление директорий

use std::fs;

fn main() -> Result<(), std::io::Error> {
    // Создание одной директории
    fs::create_dir("my_folder")?;

    // Создание вложенных директорий (как mkdir -p)
    fs::create_dir_all("a/b/c/d")?;

    // Удаление пустой директории
    fs::remove_dir("my_folder")?;

    // Удаление директории со всем содержимым (осторожно!)
    fs::remove_dir_all("a")?;
    Ok(())
}

Чтение содержимого директории

use std::fs;

fn main() -> Result<(), std::io::Error> {
    let entries = fs::read_dir(".")?;

    for entry in entries {
        let entry = entry?;
        let path = entry.path();
        let file_type = entry.file_type()?;

        if file_type.is_dir() {
            println!("[DIR] {}", path.display());
        } else if file_type.is_file() {
            println!("[FILE] {}", path.display());
        }
    }
    Ok(())
}

Получение метаданных файла

use std::fs;

fn main() -> Result<(), std::io::Error> {
    let metadata = fs::metadata("Cargo.toml")?;
    println!("Размер: {} байт", metadata.len());
    println!("Только для чтения: {}", metadata.permissions().readonly());
    println!("Время изменения: {:?}", metadata.modified());
    Ok(())
}

Продвинутые техники: буферизация, OpenOptions и обработка ошибок

Для работы с большими файлами или когда нужен тонкий контроль над процессом, используйте буферизированное чтение/запись и структуру OpenOptions.

Использование OpenOptions

OpenOptions позволяет точно настроить режим открытия файла: чтение, запись, добавление, создание и т.д.

use std::fs                

Блоги

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