Lectura eficiente de archivos en Rust

RustRustBeginner
Practicar Ahora

This tutorial is from open-source community. Access the source code

💡 Este tutorial está traducido por IA desde la versión en inglés. Para ver la versión original, puedes hacer clic aquí

Introducción

En este laboratorio, se nos da una implementación sencilla y una implementación más eficiente para leer líneas de un archivo en Rust. El enfoque sencillo utiliza read_to_string para leer el archivo en una sola cadena y luego la divide en líneas, mientras que el enfoque más eficiente utiliza un BufReader para leer el archivo línea por línea sin cargar todo el contenido en memoria.

Nota: Si el laboratorio no especifica un nombre de archivo, puede usar cualquier nombre de archivo que desee. Por ejemplo, puede usar main.rs, compilar y ejecutarlo con rustc main.rs &&./main.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL rust(("Rust")) -.-> rust/ControlStructuresGroup(["Control Structures"]) rust(("Rust")) -.-> rust/FunctionsandClosuresGroup(["Functions and Closures"]) rust(("Rust")) -.-> rust/DataStructuresandEnumsGroup(["Data Structures and Enums"]) rust(("Rust")) -.-> rust/AdvancedTopicsGroup(["Advanced Topics"]) rust(("Rust")) -.-> rust/BasicConceptsGroup(["Basic Concepts"]) rust/BasicConceptsGroup -.-> rust/variable_declarations("Variable Declarations") rust/BasicConceptsGroup -.-> rust/mutable_variables("Mutable Variables") rust/ControlStructuresGroup -.-> rust/for_loop("for Loop") rust/FunctionsandClosuresGroup -.-> rust/function_syntax("Function Syntax") rust/FunctionsandClosuresGroup -.-> rust/expressions_statements("Expressions and Statements") rust/DataStructuresandEnumsGroup -.-> rust/method_syntax("Method Syntax") rust/AdvancedTopicsGroup -.-> rust/operator_overloading("Traits for Operator Overloading") subgraph Lab Skills rust/variable_declarations -.-> lab-99272{{"Lectura eficiente de archivos en Rust"}} rust/mutable_variables -.-> lab-99272{{"Lectura eficiente de archivos en Rust"}} rust/for_loop -.-> lab-99272{{"Lectura eficiente de archivos en Rust"}} rust/function_syntax -.-> lab-99272{{"Lectura eficiente de archivos en Rust"}} rust/expressions_statements -.-> lab-99272{{"Lectura eficiente de archivos en Rust"}} rust/method_syntax -.-> lab-99272{{"Lectura eficiente de archivos en Rust"}} rust/operator_overloading -.-> lab-99272{{"Lectura eficiente de archivos en Rust"}} end

read_lines

Un enfoque sencillo

Este podría ser un primer intento razonable para la primera implementación de un principiante para leer líneas de un archivo.

use std::fs::read_to_string;

fn read_lines(filename: &str) -> Vec<String> {
    let mut result = Vec::new();

    for line in read_to_string(filename).unwrap().lines() {
        result.push(line.to_string())
    }

    result
}

Dado que el método lines() devuelve un iterador sobre las líneas del archivo, también podemos realizar un mapeo en línea y recopilar los resultados, lo que produce una expresión más concisa y fluida.

use std::fs::read_to_string;

fn read_lines(filename: &str) -> Vec<String> {
    read_to_string(filename)
     .unwrap()  // genera un panic en posibles errores de lectura de archivo
     .lines()  // divide la cadena en un iterador de rebanadas de cadena
     .map(String::from)  // convierte cada rebanada en una cadena
     .collect()  // los agrupa en un vector
}

Tenga en cuenta que en ambos ejemplos anteriores, debemos convertir la referencia &str devuelta por lines() al tipo String con propiedad, usando .to_string() y String::from respectivamente.

Un enfoque más eficiente

Aquí pasamos la propiedad del File abierto a una estructura BufReader. BufReader utiliza un búfer interno para reducir las asignaciones intermedias.

También actualizamos read_lines para devolver un iterador en lugar de asignar nuevos objetos String en memoria para cada línea.

use std::fs::File;
use std::io::{self, BufRead};
use std::path::Path;

fn main() {
    // El archivo hosts.txt debe existir en el directorio actual
    if let Ok(lines) = read_lines("./hosts.txt") {
        // Consume el iterador, devuelve una (Opcional) String
        for line in lines {
            if let Ok(ip) = line {
                println!("{}", ip);
            }
        }
    }
}

// La salida está envuelta en un Result para permitir coincidir con errores
// Devuelve un Iterador al lector de las líneas del archivo.
fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>>
where P: AsRef<Path>, {
    let file = File::open(filename)?;
    Ok(io::BufReader::new(file).lines())
}

Ejecutar este programa simplemente imprime las líneas por separado.

$ echo -e "127.0.0.1\n192.168.0.1\n" > hosts.txt
$ rustc read_lines.rs && ./read_lines
127.0.0.1
192.168.0.1

(Tenga en cuenta que dado que File::open espera un AsRef<Path> genérico como argumento, definimos nuestro método genérico read_lines() con la misma restricción genérica, usando la palabra clave where.)

Este proceso es más eficiente que crear una String en memoria con todo el contenido del archivo. Esto puede causar problemas de rendimiento especialmente al trabajar con archivos más grandes.

Resumen

¡Felicitaciones! Has completado el laboratorio Read_lines. Puedes practicar más laboratorios en LabEx para mejorar tus habilidades.