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

Archivos y E/S en Rust

Este capítulo introduce el lenguaje Rust I/Operación O.

Recibir parámetros de línea de comandos

Los programas de línea de comandos son la forma más básica de existencia de los programas de computadora, prácticamente todos los sistemas operativos admiten programas de línea de comandos y basan la ejecución de programas visuales en el mecanismo de línea de comandos.

Los programas de línea de comandos deben poder recibir parámetros del entorno de línea de comandos, estos parámetros a menudo se separan por espacios en una línea de comandos.

En muchos lenguajes (como Java y C/C++Los parámetros de entorno se pasan a los programas a través de los parámetros de la función principal (a menudo un array de cadenas de caracteres), pero en Rust, la función principal es una función sin parámetros, los parámetros de entorno necesitan ser extraídos por el desarrollador a través del módulo std::env, el proceso es muy simple:

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

Ahora ejecuta el programa directamente:

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

Quizás el resultado que obtengas sea mucho más largo que este, es normal, en este resultado, la estructura Args tiene un array inner, que solo contiene cadenas de caracteres únicas, representando la ubicación del programa en ejecución.

Pero esta estructura de datos es difícil de entender, no importa, podemos recorrerla simplemente:

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

Resultados de ejecución:

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

Los parámetros generales son para ser recorridos, ¿no es así?

Ahora abrimos el archivo launch.json que no tocamos desde hace mucho tiempo, encontramos "args": [], aquí se pueden establecer los parámetros de ejecución, lo escribimos como "args": ["first", "second"], luego guardamos y ejecutamos el programa mencionado anteriormente, el resultado de la ejecución:

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

Como un verdadero programa de línea de comandos, nunca lo hemos utilizado realmente, y como tutorial de lenguaje, no se describe aquí cómo ejecutar programas de Rust en la línea de comandos. Pero si eres un desarrollador entrenado, deberías poder encontrar la ubicación del archivo ejecutable, puedes intentar ingresar al directorio y usar comandos de línea de comandos para probar si el programa recibe parámetros de entorno de línea de comandos.

Entrada de línea de comandos

Los capítulos anteriores detallaron cómo usar la salida de línea de comandos, debido a las necesidades de aprendizaje del lenguaje, sin salida no se puede depurar el programa. Pero obtener información de entrada desde la línea de comandos es muy importante para un programa de línea de comandos.

En Rust, el módulo std::io proporciona las funciones relacionadas con la entrada estándar (que se puede considerar como entrada de línea de comandos):

use std::io::stdin;
fn main() {
let mut str_buf = String::new();
    stdin().read_line(&mut str_buf)
        .expect("Failed to read line.");
    println!("Tu línea de entrada es \n{}", str_buf);
}

Hacer que el entorno de VSCode soporte la entrada de línea de comandos es un proceso muy tedioso, que involucra problemas de plataforma y problemas de depuración, por lo que ejecutamos directamente el programa en el terminal de VSCode. En la línea de comandos, ejecuta:

D:\rust\greeting> cd ./target/debug
D:\rust\greeting\target\debug> ./greeting.exe
w3codebox
Tu línea de entrada es 
w3codebox

El paquete std::io::Stdio contiene el método read_line para leer una línea de cadena a un búfer, los valores de retorno son de tipo Result, un enumerado utilizado para传递出现的 errores, por lo que se utilizan comúnmente las funciones expect o unwrap para manejar errores.

Atención:La biblioteca estándar de Rust aún no proporciona métodos directos para leer números o datos formateados desde la línea de comandos, por lo que podemos leer una línea de cadena y usar funciones de reconocimiento de cadena para procesar los datos.

Lectura de archivos

Creamos el archivo text.txt en la carpeta D:\ del computador, con el siguiente contenido:

Este es un archivo de texto.

Este es un programa que lee el contenido de un archivo de texto en una cadena:

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

Resultados de ejecución:

Este es un archivo de texto.

Leer un archivo que puede caber en la memoria es extremadamente simple en Rust, el método read_to_string del módulo std::fs puede leer archivos de texto fácilmente.

Pero si el archivo a leer es un archivo binario, podemos usar la función std::fs::read para leerlo.8 conjunto de tipos:

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

Resultados de ejecución:

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

Estos dos métodos son lecturas de una vez, muy adecuados para el desarrollo de aplicaciones web. Pero para algunos programas de nivel inferior, el método tradicional de lectura de flujo sigue siendo insustituible, ya que en muchos casos el tamaño del archivo puede superar la capacidad de la memoria.

Manera de leer flujo de archivos en Rust:

use std::io::prelude::*;
use std::fs;
fn main() {
    let mut buffer = [0u8; 5];
    let mut file = fs::File::open("D:\\text.txt").unwrap();
    file.read(&mut buffer).unwrap();
    println!("{:?}", buffer);
    file.read(&mut buffer).unwrap();
    println!("{:?}", buffer);
}

Resultados de ejecución:

[84, 104, 105, 115, 32] 
[105, 115, 32, 97, 32]

La clase File del módulo std::fs es una clase que describe archivos, y se puede usar para abrir archivos. Después de abrir el archivo, podemos usar el método read de File para leer algunos bytes inferiores del archivo al búfer (el búfer es un u8 de array), el número de bytes leídos es igual a la longitud del búfer.

Nota: Actualmente, VSCode no tiene la función de agregar automáticamente referencias a bibliotecas estándar, por lo que los errores como "función o método no existe" pueden deberse a problemas de referencias a bibliotecas estándar. Podemos ver los comentarios de la documentación de la biblioteca estándar (al pasar el ratón sobre ellos) para agregar manualmente la biblioteca estándar.

El método open de std::fs::File abre el archivo en modo "solo lectura" y no tiene un método de cierre complementario, porque el compilador de Rust puede cerrar el archivo automáticamente cuando ya no se utilice.

Escritura de archivos

La escritura de archivos se divide en escritura de una vez y escritura de flujo. La escritura de flujo requiere abrir el archivo, y hay dos formas de abrirlo: "nuevo" (create) y "añadir" (append).

Escritura de una vez:

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

Esto es tan simple y conveniente como leer de una vez. Después de ejecutar el programa, el contenido del archivo D:\text.txt será reescrito como FROM RUST PROGRAM. Por lo tanto, utilice la escritura de una vez con precaución, ya que eliminará directamente el contenido del archivo (independientemente de su tamaño). Si el archivo no existe, se creará.

Si desea escribir contenido en un archivo de manera de flujo, puede usar el método create de 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();
}

Este programa es equivalente al programa anterior.

Atención¡El archivo abierto debe estar almacenado en una variable mutable para poder usar los métodos de File!

No existe el método estático append en la clase File, pero podemos usar OpenOptions para abrir archivos con métodos específicos:

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(())
}

Después de ejecutar, el contenido del archivo D:\text.txt se convertirá en:

FROM RUST PROGRAM APPEND WORD

OpenOptions es un método flexible para abrir archivos, que puede configurar permisos de apertura, además de append, también tiene permisos de lectura y escritura. Si queremos abrir un archivo con permisos de lectura y escritura, podemos escribirlo así:

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(())
}

Después de ejecutar, el contenido del archivo D:\text.txt se convertirá en:

COVERRUST PROGRAM APPEND WORD