English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Файлы и IO в Rust

Эта глава знакомит с операциями ввода-вывода в языке Rust.

Получение параметров командной строки

Командные строковые программы являются наиболее базовой формой существования компьютерных программ, почти все операционные системы поддерживают командные строковые программы и основывают визуальное выполнение на механизме командной строки.

Командные строковые программы должны быть способны принимать параметры из окружения командной строки, эти параметры часто разделены пробелом после команды в командной строке.

Во многих языках (например, Java и C/C++) параметры окружения передаются программе через параметры главного функции (часто это массив строк), но в Rust главный функция является функцией без параметров, параметры окружения необходимо извлекать разработчиком через модуль std::env, процесс очень прост:

fn main() {
    let args = std::env::args();
    println!("{:?}", args);
}

Теперь напрямую запускайте программу:

Args { inner: ["D:\\rust\\greeting\\target\\debug\\greeting.exe"] }

Возможно, вы получите результат, который длиннее этого, это совершенно нормально, в этом результате Args структура содержит массив inner, который содержит только уникальные строки, представляющие местоположение текущей программы.

Но эта структура данных трудна для понимания, не волнуйтесь, мы можем просто итерировать ее:

fn main() {
    let args = std::env::args();
    for arg in args {
        println!("{}", arg);
    }
}

println!("{:?}", buffer);

D:\rust\greeting\target\debug\greeting.exe

Обычные параметры используются для итерации, не так ли?

Теперь мы открываем давно не используемый файл launch.json, находим "args": [], здесь можно установить параметры выполнения, мы пишем "args": ["first", "second"]", затем сохраняем и снова запускаем только что созданную программу, результат выполнения:

D:\rust\greeting\target\debug\greeting.exe
first
second

Как настоящий командный строковый программа, мы никогда не использовали его, как учебник по языку не рассказывает, как запускать Rust программы из командной строки. Но если вы опытный разработчик, вы должны найти местоположение исполняемого файла, вы можете попробовать перейти в каталог и использовать командные строки для тестирования программы на принятие командной строки параметров.

Ввод в командной строке

Ранние главы подробно рассказывают о том, как использовать вывод в командной строке, это необходимо для изучения языка, без вывода программу невозможно отладить. Но информация, полученная из ввода в командной строке, для командной строки программы по-прежнему очень важна.

В Rust std::io модуль предоставляет функции для стандартного ввода (можно считать вводом из командной строки):

use std::io::stdin;
fn main() {
let mut str_buf = String::new()
    stdin().read_line(&mut str_buf)
        .expect("Не удалось прочитать строку.");
    println!("Ваш ввод в строке \n{}", str_buf);
}

Поддержка командной строки в среде VSCode может быть очень сложной задачей, связанной с跨platformными проблемами и проблемами отладки, поэтому мы напрямую запускаем программу в терминале VSCode. В командной строке выполняем:

D:\rust\greeting> cd ./target/debug
D:\rust\greeting\target\debug> ./greeting.exe
w3codebox
Ваш ввод в строке: 
w3codebox

Пакет std::io::Stdio содержит метод read_line для чтения строки в буфер, возвращаемое значение - это тип Result, который используется для передачи出现的 ошибок, поэтому часто используются функции expect или unwrap для обработки ошибок.

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

Чтение файла

Мы создаем файл text.txt в каталоге D:\ на компьютере, содержимое файла следующее:

Это текстовый файл.

Это программа, которая читает содержимое текстового файла в строку:

use std::fs;
fn main() {
    let text = fs::read_to_string("D:\\text.txt").unwrap();
    println!("{}", text);
}

println!("{:?}", buffer);

Это текстовый файл.

В Rust чтение целого файла, который может поместиться в память, является极其 простым процессом, метод read_to_string из модуля std::fs позволяет легко читать текстовые файлы.

Если нужно прочитать файл в двоичном формате, мы можем использовать функцию read из std::fs::read для чтения набора типов u8:

use std::fs;
fn main() {
    let content = fs::read("D:\\text.txt").unwrap();
    println!("{:?}", content);
}

println!("{:?}", buffer);

[84, 104, 105, 115, 32, 105, 115, 32, 97, 32, 116, 101, 120, 116, 32, 102, 105, 108, 101, 46]

以上两种方式是一次性读取,十分适合 Web 应用的开发。但是对于一些底层程序来说,传统的按流读取的方式依然是无法被取代的,因为更多情况下文件的大小可能远超内存容量。

Эти два способа являются одноразовыми чтениями и очень подходят для разработки веб-приложений. Но для некоторых底层 программ традиционный способ потокового чтения по-прежнему незаменим, потому что в большинстве случаев размер файла может быть значительно больше объема памяти.

use std::io::prelude::*;
use std::fs;
fn main() {
    Способ потокового чтения файлов в Rust:
    let mut buffer = [0u8; 5];
    let mut file = fs::File::open("D:\\text.txt").unwrap();
    file.read(&mut buffer).unwrap();
    let mut file = fs::File::open("D:\\text.txt").unwrap();
    file.read(&mut buffer).unwrap();
}

println!("{:?}", buffer);

Результат выполнения: 
[84, 104, 105, 115, 32]

[105, 115, 32, 97, 32]

Внимание: в настоящее время VSCode не имеет функции автоматического добавления стандартных библиотек, поэтому ошибки, такие как "функция или метод не существует", могут быть связаны с проблемами ссылок на стандартные библиотеки. Мы можем проверить комментарии к документации стандартной библиотеки (при наведении мыши会出现) и вручную добавить стандартную библиотеку.

Метод open класса std::fs::File открывает файл в режиме "только чтение", и у него нет配套的方法 close, потому что компилятор Rust может автоматически закрывать файл, когда он больше не используется.

Запись файла

Запись файла делится на одноразовую запись и потоковую запись. Потоковая запись требует открытия файла, а способ открытия файла есть "создание" (create) и "добавление" (append).

Одноразовое写入:

use std::fs;
fn main() {
    fs::write("D:\\text.txt", "FROM RUST PROGRAM")
        .unwrap();
}

Это так же просто и удобно, как и одноразовое чтение. После выполнения программы, содержимое файла D:\text.txt будет перезаписано как FROM RUST PROGRAM. Поэтому, будьте осторожны при одноразовом写入!因为它 напрямую удалит содержимое файла (независимо от его размера). Если файл не существует, он будет создан.

Если нужно写入文件内容的方式是流овый, можно использовать метод create класса std::fs::File:

use std::io::prelude::*;
use std::fs::File;
fn main() {
    let mut file = File::create("D:\\text.txt").unwrap();
    file.write(b"FROM RUST PROGRAM").unwrap();
}

Этот код эквивалентен предыдущему.

ВниманиеФайл, открытый с помощью File, должен храниться в изменяемой переменной, чтобы можно было использовать методы File!

В классе File не существует статического метода append, но мы можем использовать OpenOptions для открытия файла с помощью определенного метода:

use std::io::prelude::*;
use std::fs::OpenOptions;
fn main() -> std::io::Result<()> {
    
    let mut file = OpenOptions::new()
            .append(true).open("D:\\text.txt")?;
    file.write(b" APPEND WORD")?;
    Ok(())
}

После выполнения, содержимое файла D:\text.txt изменится:

FROM RUST PROGRAM APPEND WORD

OpenOptions - это гибкий способ открывать файлы, он может устанавливать права доступа, кроме режима append, также есть права доступа read и write. Если мы хотим открыть файл с правами чтения и записи, можно написать так:

use std::io::prelude::*;
use std::fs::OpenOptions;
fn main() -> std::io::Result<()> {
    
    let mut file = OpenOptions::new()
            .read(true).write(true).open("D:\\text.txt")?;
    file.write(b"COVER")?;
    Ok(())
}

После выполнения, содержимое файла D:\text.txt изменится:

COVERRUST PROGRAM APPEND WORD