Files
Link: https://rust.nizeclub.ru/_12.html#part01
Ввод-вывод построен вокруг модуля стандартной библиотеки std::io, который предоставляет инструменты для работы с потоками данных, а также модуля std::fs, предназначенного для операций с файловой системой.
Чтение файлов
Чтение текста из файлов в строку
Для чтения файлов, нужно сначала добавить несколько методов из библиотек: FIle - открытие файлов и Read - чтение.
use std::fs::File; // импорт File
use std::io::Read; // импорт Read
fn main() -> std::io::Result<()> { // отлов ошибок ввода/вывода
let filename = "test.txt".to_string(); // путь до файла в корне проекта
let mut filetext = String::new();
let mut filehandle = File::open(filename)?;
filehandle.read_to_string(&mut filetext)?; // чтение в строку
println!("{filetext}");
Ok(())
}Чтение в вектор из байтов (vector of bytes)
Чтение файла в память целиком как вектора байтов - для бинарных файлов, либо для частого обращения к содержимому:
use std::io::Read;
use std::{env, fs, io, str};
fn main() -> io::Result<()> {
let mut file = fs::File::open("test_file.txt")?;
let mut contents = Vec::new();
file.read_to_end(&mut contents);
println!("File contents: {:?}", contents); // вывод байт
let text = match str::from_utf8(&contents) { // перевод в строку UTF8
Ok(v) => v,
Err(e) => panic!("Invalid UTF-8: {e}"),
};
println!("Result: {text}"); // вывод строкой
Ok(())
}Запись в файлы
use std::fs::File;
use std::io::Write;
fn main() -> io::Result<()> {
// создать новый файл или обнулить имеющийся:
let mut file = File::create("report.log")?;
file.write_all(b"report.log"); // запись байтов в файл
Ok(())
}Буферизация
Чтение текста через буфер
Нужно добавить к библиотеке File также библиотеку организации буфера чтения, а также обработать ошибки открытия файла и чтения.
use std::fs::File;
use std::io::{BufReader, Read};
fn main() -> std::io::Result<()> {
let file = File::open("sportinv.csv")?;
// обернуть File в буферизированный читатель (блоки по 8kb by default):
let mut reader = BufReader::new(file);
let mut text = String::new();
reader.read_to_string(&mut text)?;
println!("{text}");
Ok(())
}Чтение текста из больших файлов в буфер по строчкам
use std::io::{BufRead, BufReader};
use std::fs::File;
fn main() -> io::Result<()> {
let file = File::open("input.txt")?;
let reader = BufReader::new(file);
for line in reader.lines() { // io::BufRead::lines() итератор
let line = line?;
println!("{line}");
}
Ok(())Запись в файл через буфер
use std::fs::File;
use std::io::{BufWriter, Write};
fn main() -> std::io::Result<()> {
let file = File::create("output.txt")?;
let mut writer = BufWriter::new(file);
writer.write_all(b"Test output!")?;
writer.flush()?; // Сброс буфера в файл
Ok(())
}Запись и дополнение файла через буфер по строчкам
use std::fs::File;
use std::io::{BufWriter, Write};
fn main() -> std::io::Result<()> {
let file = File::create("output.txt")?;
let mut writer = BufWriter::new(file);
writeln!(writer, "Первая строка")?; // макрос записи в поток
writeln!(writer, "Вторая строка")?;
writer.flush()?;
Ok(())
}File::create всегда обнуляет файл, если он уже есть. Чтобы дописать файл, нужно использовать OpenOptions и указать режим append:
use std::fs::OpenOptions; // OpenOptions вместо File
use std::io::{BufWriter, Write};
fn main() -> std::io::Result<()> {
let file = OpenOptions::new()
.append(true) // +режим дозаписи
.create(true) // создать, если файла нет
.open("output.txt")?; // открыть файл
//let file = File::create("output.txt")?;
let mut writer = BufWriter::new(file);
writeln!(writer, "Первая строка")?;
writeln!(writer, "Вторая строка")?;
writer.flush()?;
Ok(())
}Копирование файлов
Функция std::fs::copy принимает исходный и целевой пути и возвращает Result<u64, std::io::Error>, где u64 — количество скопированных байт.
use std::fs;
use std::path::Path;
fn main() {
let sourcefile = "source.txt";
let destfile = "dest.txt";
if Path::new(sourcefile).exists() {
match fs::copy(sourcefile, destfile) {
Ok(bytes) => println!("Copied {bytes} bytes"),
Err(e) => println!("Error: {e}"),
}
} else {
println!("Исходного файла НЕТ!");
}
}Если целевой файл уже существует, он будет перезаписан.
Перемещение файлов
Функция std::fs::rename принимает исходный и целевой пути и возвращает Result<(), std::io::Error> (при успехе ничего не возвращает (()), при ошибке — описание проблемы):
use std::fs;
fn main() {
match fs::rename("old.txt", "new.txt") {
Ok(()) => println!("Move successful"),
Err(e) => println!("Move failed {e}"),
}
}- Если целевой файл существует, он будет перезаписан (на той же файловой системе);
- Перемещение между разными файловыми системами может не сработать, надо сначала скопировать, а затем удалить исходный файл вручную.
Удаление файлов
Функция std::fs::remove_file принимает путь к файлу и возвращает результат типа Result<(), std::io::Error>, что позволяет обработать возможные ошибки (например, если файла не существует):
use std::fs;
fn main() {
match fs::remove_file("sport.csv") {
Ok(()) => println!("Remove successful"),
Err(e) => println!("Remove failed {e}"),
}
}Аналогично с папками:
fs::remove_file— для файлов.fs::remove_dir— для пустых директорий.fs::remove_dir_all— для директорий с содержимым.
Пути в файловой системе
Пути в Rust обрабатываются через структуры Path и PathBuf, где Path — это неизменяемый срез пути, аналогичный str:
use std::path::Path;
fn main() {
let path = 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:
use std::path::PathBuf;
fn main() {
let mut path = PathBuf::from("/home/alex/");
// push добавляет компонент к пути с учетом разделителей ОС:
path.push("test.txt");
println!("Path: {:?}", path); // /home/alex/test.txt
}Используйте Path для проверки существующих путей, а PathBuf — для построения новых.
Получить список файлов
Функция read_dir:
use std::fs;
fn main() {
let paths = fs::read_dir("./").unwrap();
for path in paths {
println!("{}", path.unwrap().path().display())
}
}Системные команды
Основной инструмент для запуска внешних программ — это модуль std::process, в частности структуры Command и Output.
Получить список файлов с их абсолютным путём в системе
use std::fs;
use std::process;
fn main() {
let paths = fs::read_dir("./").unwrap();
for path in paths {
let pathbuf = path.unwrap().path();
println!("{:?}", fs::canonicalize(&pathbuf));
}
println!("\nPID = {}\n", process::id());
}