Ввод-вывод построен вокруг модуля стандартной библиотеки std::io, который предоставляет инструменты для работы с потоками данных, а также модуля std::fs, предназначенного для операций с файловой системой.
Чтение файлов
Чтение текста из файлов в строку
Для чтения файлов, нужно сначала добавить несколько методов из библиотек: FIle - открытие файлов и Read - чтение.
usestd::fs::File;// импорт File
usestd::io::Read;// импорт Read
fnmain()-> std::io::Result<()>{// отлов ошибок ввода/вывода
letfilename="test.txt".to_string();// путь до файла в корне проекта
letmutfiletext=String::new();letmutfilehandle=File::open(filename)?;filehandle.read_to_string(&mutfiletext)?;// чтение в строку
println!("{filetext}");Ok(())}
Чтение в вектор из байтов (vector of bytes)
Чтение файла в память целиком как вектора байтов - для бинарных файлов, либо для частого обращения к содержимому:
usestd::io::Read;usestd::{env,fs,io,str};fnmain()-> io::Result<()>{letmutfile=fs::File::open("test_file.txt")?;letmutcontents=Vec::new();file.read_to_end(&mutcontents);println!("File contents: {:?}",contents);// вывод байт
lettext=matchstr::from_utf8(&contents){// перевод в строку UTF8
Ok(v)=>v,Err(e)=>panic!("Invalid UTF-8: {e}"),};println!("Result: {text}");// вывод строкой
Ok(())}
Запись в файлы
usestd::fs::File;usestd::io::Write;fnmain()-> io::Result<()>{// создать новый файл или обнулить имеющийся:
letmutfile=File::create("report.log")?;file.write_all(b"report.log");// запись байтов в файл
Ok(())}
Буферизация
Чтение текста через буфер
Нужно добавить к библиотеке File также библиотеку организации буфера чтения, а также обработать ошибки открытия файла и чтения.
usestd::fs::File;usestd::io::{BufReader,Read};fnmain()-> std::io::Result<()>{letfile=File::open("sportinv.csv")?;// обернуть File в буферизированный читатель (блоки по 8kb by default):
letmutreader=BufReader::new(file);letmuttext=String::new();reader.read_to_string(&muttext)?;println!("{text}");Ok(())}
Чтение текста из больших файлов в буфер по строчкам
usestd::fs::File;usestd::io::{BufWriter,Write};fnmain()-> std::io::Result<()>{letfile=File::create("output.txt")?;letmutwriter=BufWriter::new(file);writer.write_all(b"Test output!")?;writer.flush()?;// Сброс буфера в файл
Ok(())}
Запись и дополнение файла через буфер по строчкам
usestd::fs::File;usestd::io::{BufWriter,Write};fnmain()-> std::io::Result<()>{letfile=File::create("output.txt")?;letmutwriter=BufWriter::new(file);writeln!(writer,"Первая строка")?;// макрос записи в поток
writeln!(writer,"Вторая строка")?;writer.flush()?;Ok(())}
File::create всегда обнуляет файл, если он уже есть. Чтобы дописать файл, нужно использовать OpenOptions и указать режим append:
usestd::fs::OpenOptions;// OpenOptions вместо File
usestd::io::{BufWriter,Write};fnmain()-> std::io::Result<()>{letfile=OpenOptions::new().append(true)// +режим дозаписи
.create(true)// создать, если файла нет
.open("output.txt")?;// открыть файл
//let file = File::create("output.txt")?;
letmutwriter=BufWriter::new(file);writeln!(writer,"Первая строка")?;writeln!(writer,"Вторая строка")?;writer.flush()?;Ok(())}
Копирование файлов
Функция std::fs::copy принимает исходный и целевой пути и возвращает Result<u64, std::io::Error>, где u64 — количество скопированных байт.
Если целевой файл уже существует, он будет перезаписан.
Перемещение файлов
Функция std::fs::rename принимает исходный и целевой пути и возвращает Result<(), std::io::Error> (при успехе ничего не возвращает (()), при ошибке — описание проблемы):
Если целевой файл существует, он будет перезаписан (на той же файловой системе);
Перемещение между разными файловыми системами может не сработать, надо сначала скопировать, а затем удалить исходный файл вручную.
Удаление файлов
Функция std::fs::remove_file принимает путь к файлу и возвращает результат типа Result<(), std::io::Error>, что позволяет обработать возможные ошибки (например, если файла не существует):
Пути в Rust обрабатываются через структуры Path и PathBuf, где Path — это неизменяемый срез пути, аналогичный str:
usestd::path::Path;fnmain(){letpath=Path::new("/home/alex/example.txt");// ссылка на путь
println!("Extension: {:?}",path.extension());// Some("txt")
println!("File name: {:?}",path.file_name());// Some("example.txt")
println!("File exists? {}",path.exists());// false
}
Методы вроде extension() и file_name() возвращают Option, т.к. путь может не содержать этих элементов.
PathBuf — это изменяемая версия пути, аналогичная String:
usestd::path::PathBuf;fnmain(){letmutpath=PathBuf::from("/home/alex/");// push добавляет компонент к пути с учетом разделителей ОС:
path.push("test.txt");println!("Path: {:?}",path);// /home/alex/test.txt
}
Используйте Path для проверки существующих путей, а PathBuf — для построения новых.
Чтение файла по имени из строки или PathBuf
Объект PathBuf реализует AsRef trait, это даёт возможность универсально передавать его:
usestd::fs;usestd::path::Path;// Функция забирает как строку, так и Path объект
fnread_file<P: AsRef<Path>>(path: P)-> String{// .as_ref() переводит полученное в &Path
fs::read_to_string(path.as_ref()).unwrap()}fnmain(){// оба работают:
letcontent1=read_file("hello.txt");// &str
letcontent2=read_file(Path::new("world.txt"));// &Path
}