Rust: с нуля до своего органайзера Урок 50 из 55
Чтение и запись файлов
Урок 50. Записать текст, прочитать его и объяснить отказ ввода-вывода.
Текст переведён с помощью ИИ.
Предварительно: Result, передача ошибки и пути. Это отдельный учебный файл во временной папке, не данные настоящего органайзера.
Образ и опорная карта
Запись в тетрадь может не состояться: тетрадь не нашли, к ней нет доступа или текст испорчен. Ввод-вывод (I/O) — работа программы с внешним миром, в том числе с файлами. Result сообщает успех или конкретную ошибку. Предел образа: файл может измениться между проверкой и чтением, поэтому наличие пути заранее не гарантирует успех последующей операции.
выбрать отдельный временный путь → создать без перезаписи → записать байты → закрыть → прочитать UTF-8 → удалить → обработать ошибку. temp_dir() даёт системную временную папку; process::id() добавляет номер текущего процесса к учебному имени. create_new(true) требует нового файла и не перезапишет существующий. write_all — метод трейта Write, поэтому его импортируют; он пытается записать все байты текста. as_bytes() переводит UTF-8 строку в байты без потери. drop(file) закрывает открытый файл до чтения, что важно и для Windows. read_to_string читает весь файл как UTF-8: отсутствие файла, отказ доступа и неверный UTF-8 дают Err. ? передаёт ошибку из run, а std::io::Result<()> означает успех без дополнительного значения. eprintln! печатает ошибку отдельно от обычного результата. ErrorKind обозначает вид ошибки; NotFound значит, что файл не найден.
std::process::exit(1) завершает программу с кодом 1 при неустранённой ошибке; код 0 означал бы успех и ввёл бы вызывающую программу в заблуждение.
Сохраните и снова прочитайте учебную строку
На телефоне длинную строку кода можно сдвинуть пальцем внутри светлой рамки; вся страница при этом не расширяется.
use std::fs::{self, OpenOptions};
use std::io::Write;
fn run() -> std::io::Result<()> {
let path = std::env::temp_dir().join(format!("rust-lesson-50-{}.txt", std::process::id()));
let mut file = OpenOptions::new()
.write(true)
.create_new(true)
.open(&path)?;
file.write_all("Купить книгу\n".as_bytes())?;
drop(file);
let text = fs::read_to_string(&path)?;
print!("{text}");
fs::remove_file(&path)?;
Ok(())
}
fn main() {
if let Err(error) = run() {
eprintln!("Ошибка файла: {error}");
std::process::exit(1);
}
}
Купить книгу
После чтения remove_file удаляет только этот учебный файл. При ошибке до удаления он может остаться во временной папке; приложение должно учитывать такой случай. create_new при следующем совпадении имени вернёт ошибку и не затрёт старое содержимое. Здесь нет постоянного хранения органайзера: безопасное сохранение и восстановление будут позже.
Вопросы для воспроизведения
- Чем
create_new(true)защищает данные? - Почему
read_to_stringможет вернутьErrдаже при существующем файле? - Где будет видна ошибка из
eprintln!?
Задание
Обязательное. После удаления попробуйте fs::read_to_string(&path) ещё раз. Через match и ErrorKind::NotFound выведите Файл отсутствует; для неожиданных успеха и ошибки предусмотрите отдельные ветви. Сначала предскажите результат.
Ответы
Показать ответы
Добавьте use std::io::{ErrorKind, Write};. После remove_file сравните error.kind() с ErrorKind::NotFound; не сравнивайте текст сообщения ОС, он зависит от языка и системы.
use std::fs::{self, OpenOptions};
use std::io::{ErrorKind, Write};
fn run() -> std::io::Result<()> {
let path = std::env::temp_dir().join(format!("rust-lesson-50-{}.txt", std::process::id()));
let mut file = OpenOptions::new()
.write(true)
.create_new(true)
.open(&path)?;
file.write_all("Купить книгу\n".as_bytes())?;
drop(file);
let text = fs::read_to_string(&path)?;
print!("{text}");
fs::remove_file(&path)?;
match fs::read_to_string(&path) {
Err(error) if error.kind() == ErrorKind::NotFound => println!("Файл отсутствует"),
Ok(_) => println!("Неожиданный успех"),
Err(error) => eprintln!("Ошибка файла: {error}"),
}
Ok(())
}
fn main() {
if let Err(error) = run() {
eprintln!("Ошибка файла: {error}");
std::process::exit(1);
}
}
Купить книгу
Файл отсутствует
После проверки
Если файл недоступен, error.kind() может быть PermissionDenied; если байты не образуют UTF-8, read_to_string тоже вернёт ошибку. Не показывайте такие случаи как пустой список задач. Для настоящих данных нужно ещё защитить запись от обрыва и сохранить копию: следующие уроки разбирают это отдельно. Официальная документация read_to_string.
Если вы нашли ошибку или опечатку в тексте статьи, то сообщите нам об этом
Комментарии (0)
Войдите, чтобы оставить комментарий →
Пока нет комментариев. Будьте первым.