Leyendo un archivo

Ahora agregaremos funcionalidad para leer el archivo especificado en el argumento file_path. Primero, necesitamos un archivo de muestra para probarlo: ¡usaremos un archivo con una pequeña cantidad de texto en varias líneas con algunas palabras repetidas! ¡El Listado 12-3 tiene un poema de Emily Dickinson que funcionará bien! Cree un archivo llamado poem.txt en el nivel raíz de su proyecto e ingrese el poema "¡Soy nadie! ¿Quién eres tú?"

Filename: poem.txt

I'm nobody! Who are you?
Are you nobody, too?
Then there's a pair of us - don't tell!
They'd banish us, you know.

How dreary to be somebody!
How public, like a frog
To tell your name the livelong day
To an admiring bog!

Listing 12-3: Un poema de Emily Dickinson sirve como buen caso de test

Con el texto en su lugar, edite src/main.rs y agregue código para leer el archivo, como se muestra en el Listado 12-4.

Filename: src/main.rs

use std::env;
use std::fs;

fn main() {
    // --snip--
    let args: Vec<String> = env::args().collect();

    let query = &args[1];
    let file_path = &args[2];

    println!("Searching for {query}");
    println!("In file {file_path}");

    let contents = fs::read_to_string(file_path)
        .expect("Should have been able to read the file");

    println!("With text:\n{contents}");
}

Listing 12-4: Leyendo el contenido del archivo especificado por el segundo argumento

Primero, importamos la parte relevante de la biblioteca estándar con una sentencia use: necesitamos std::fs para manejar archivos.

En main, la nueva sentencia fs::read_to_string toma el file_path, abre ese archivo y devuelve un std::io::Result<String> del contenido del archivo.

Luego, nuevamente agregamos una declaración println! temporal que imprime el valor de contents después de que se lee el archivo, para que podamos verificar que el programa está funcionando hasta ahora.

Ejecutemos este código con cualquier string como primer argumento de la línea de comandos (porque aún no hemos implementado la parte de búsqueda) y el archivo poem.txt como segundo argumento:

$ cargo run -- the poem.txt
   Compiling minigrep v0.1.0 (file:///projects/minigrep)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.0s
     Running `target/debug/minigrep the poem.txt`
Searching for the
In file poem.txt
With text:
I'm nobody! Who are you?
Are you nobody, too?
Then there's a pair of us - don't tell!
They'd banish us, you know.

How dreary to be somebody!
How public, like a frog
To tell your name the livelong day
To an admiring bog!

¡Genial! El código leyó el archivo y luego imprimió el contenido del archivo. Pero el código tiene algunas fallas. En este momento, la función main tiene múltiples responsabilidades: en general, las funciones son más claras y más fáciles de mantener si cada función es responsable de una sola idea. El otro problema es que no estamos manejando los errores tan bien como podríamos. El programa todavía es pequeño, por lo que estas fallas no son un gran problema, pero a medida que el programa crece, será más difícil corregirlos de manera limpia. Es una buena práctica comenzar a refactorizar desde el principio al desarrollar un programa, porque es mucho más fácil refactorizar cantidades menores de código. Haremos eso a continuación.