Lendo um Arquivo
Agora vamos adicionar funcionalidades para ler o arquivo que é especificado no
argumento filename
da linha de comando. Primeiro, precisamos de um arquivo de amostra para testá-lo:
o melhor tipo de arquivo a ser usado para garantir que o minigrep
esteja funcionando é um ,com uma
pequena quantidade de texto, em várias linhas com algumas palavras repetidas. Listagem 12-3
tem um poema de Emily Dickinson que funcionará bem! Crie um arquivo chamado
poem.txt no diretório raiz do seu projeto e entre com o poema “I’m Nobody!
Who are you?”
Arquivo: 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!
Com o texto no lugar, edite src/main.rs e adicione o código para abrir o arquivo, como mostrado na Listagem 12-4:
Arquivo: src/main.rs
use std::env; use std::fs::File; use std::io::prelude::*; fn main() { let args: Vec<String> = env::args().collect(); let query = &args[1]; let filename = &args[2]; println!("Searching for {}", query); // --snip-- println!("In file {}", filename); let mut f = File::open(filename).expect("file not found"); let mut contents = String::new(); f.read_to_string(&mut contents) .expect("something went wrong reading the file"); println!("With text:\n{}", contents); }
Primeiro, adicionamos mais instruções use
para trazer partes relevantes da
biblioteca padrão: precisamos de std::fs::File
para lidar com arquivos, e
std::io::prelude::*
contém vários traits úteis para fazer E/S, incluindo
arquivo de E/S. Da mesma forma que Rust tem um prelúdio geral que traz certos
tipos e funções no escopo automaticamente, o módulo std::io
possui o seu próprio
prelúdio de tipos e funções comuns que você precisará ao trabalhar com E/S. Ao contrário
do prelúdio padrão, devemos adicionar explicitamente uma instrução use
para o prelúdio
de std::io
.
Em main
, adicionamos três declarações: primeiro, recebemos um identificador mutável para o
arquivo chamando a função File::open
e transmitindo o valor da
variável filename
. Em segundo lugar, criamos uma variável chamada contents
e configuramos
para uma String
mutável e vazia. Isso manterá o conteúdo do arquivo depois que nós
lê-lo. Terceiro, chamamos read_to_string
no nosso arquivo e passamos um
referência mutável para contents
como argumento.
Após essas linhas, adicionamos novamente uma declaração temporária println!
que
imprime o valor do contents
depois que o arquivo é lido, para que possamos verificar que o
o programa está funcionando até o momento.
Vamos executar este código com qualquer string como o primeiro argumento da linha de comando (porque ainda não implementamos a parte de pesquisa) e o arquivo poem.txt como o segundo argumento:
$ cargo run the poem.txt
Compiling minigrep v0.1.0 (file:///projects/minigrep)
Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs
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!
Ótimo! O código lê e, em seguida, imprime o conteúdo do arquivo. Mas o código tem
algumas falhas. A função main
tem múltiplas responsabilidades: geralmente,
as funções são mais claras e fáceis de manter se cada função for responsável
por apenas uma idéia. O outro problema é que também não estamos lidando com erros,
como poderíam ser. O programa ainda é pequeno, então essas falhas não são um grande problema,
mas à medida que o programa cresce, será mais difícil consertá-los de forma elegante. É uma boa
pratica começar a refatoração no início do desenvolvimento de um programa, porque são
muito mais fáceis de refatorar quantidades menores de código. Vamos fazer isso depois.