Ler Arquivo em Rust

Aprenda como ler arquivo em Rust com fs::read_to_string(), BufReader, leitura linha por linha e tratamento de erros. Exemplos completos.

Ler Arquivo em Rust

Ler arquivos é uma operação essencial em qualquer programa. Rust fornece APIs seguras e eficientes para leitura de arquivos, desde métodos simples para arquivos pequenos até leitura bufferizada para arquivos grandes.

Ler arquivo inteiro com fs::read_to_string()

A forma mais simples de ler um arquivo inteiro para uma String:

use std::fs;

fn main() {
    // Forma mais simples — arquivo inteiro em uma String
    match fs::read_to_string("exemplo.txt") {
        Ok(conteudo) => {
            println!("Conteúdo ({} bytes):", conteudo.len());
            println!("{}", conteudo);
        }
        Err(e) => eprintln!("Erro ao ler arquivo: {}", e),
    }
}

Saída (com arquivo exemplo.txt contendo “Olá Rust!\nSegunda linha”):

Conteúdo (27 bytes):
Olá Rust!
Segunda linha

Ler arquivo com tratamento robusto de erros

Em código de produção, use o operador ? com funções que retornam Result:

use std::fs;
use std::io;
use std::path::Path;

fn ler_arquivo_seguro(caminho: &str) -> Result<String, io::Error> {
    let path = Path::new(caminho);

    // Verificar se o arquivo existe
    if !path.exists() {
        return Err(io::Error::new(
            io::ErrorKind::NotFound,
            format!("Arquivo não encontrado: {}", caminho),
        ));
    }

    // Verificar se é um arquivo (não diretório)
    if !path.is_file() {
        return Err(io::Error::new(
            io::ErrorKind::InvalidInput,
            format!("Não é um arquivo: {}", caminho),
        ));
    }

    fs::read_to_string(caminho)
}

fn main() {
    match ler_arquivo_seguro("config.toml") {
        Ok(conteudo) => println!("Config:\n{}", conteudo),
        Err(e) => eprintln!("Erro: {}", e),
    }

    // Múltiplos arquivos com tratamento individual
    let arquivos = vec!["dados.txt", "config.toml", "notas.md"];
    for arquivo in arquivos {
        match fs::read_to_string(arquivo) {
            Ok(c) => println!("✓ {} ({} bytes)", arquivo, c.len()),
            Err(e) => println!("✗ {}: {}", arquivo, e),
        }
    }
}

Ler arquivo linha por linha com BufReader

Para arquivos grandes, use BufReader para ler linha por linha sem carregar tudo na memória:

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

fn main() -> io::Result<()> {
    let arquivo = File::open("dados.txt")?;
    let leitor = BufReader::new(arquivo);

    // Ler linha por linha
    for (numero, linha) in leitor.lines().enumerate() {
        let linha = linha?; // lines() retorna Result por linha
        println!("{:4}: {}", numero + 1, linha);
    }

    Ok(())
}

Saída (com arquivo de exemplo):

   1: Primeira linha do arquivo
   2: Segunda linha com dados
   3: Terceira linha final

Exemplo prático: processar arquivo de log

Um exemplo mais completo que lê um arquivo de log, filtra por nível e conta ocorrências:

use std::collections::HashMap;
use std::fs::File;
use std::io::{self, BufRead, BufReader};

fn processar_log(caminho: &str) -> io::Result<()> {
    let arquivo = File::open(caminho)?;
    let leitor = BufReader::new(arquivo);

    let mut contagem: HashMap<String, usize> = HashMap::new();
    let mut total = 0;

    for linha in leitor.lines() {
        let linha = linha?;
        total += 1;

        // Extrair nível de log (ex: "2026-02-23 ERROR mensagem")
        if let Some(nivel) = linha.split_whitespace().nth(1) {
            *contagem.entry(nivel.to_string()).or_insert(0) += 1;
        }
    }

    println!("Total de linhas: {}", total);
    println!("Contagem por nível:");
    for (nivel, quantidade) in &contagem {
        println!("  {}: {}", nivel, quantidade);
    }

    Ok(())
}

fn main() {
    if let Err(e) = processar_log("servidor.log") {
        eprintln!("Erro ao processar log: {}", e);
    }
}

Ler arquivo binário (bytes)

Para arquivos que não são texto puro, leia como bytes:

use std::fs;
use std::io::{self, Read};

fn main() -> io::Result<()> {
    // Ler tudo como Vec<u8>
    let bytes = fs::read("imagem.png")?;
    println!("Tamanho: {} bytes", bytes.len());
    println!("Primeiros 16 bytes: {:?}", &bytes[..16.min(bytes.len())]);

    // Ler chunks com BufReader
    let mut arquivo = fs::File::open("dados.bin")?;
    let mut buffer = [0u8; 1024]; // buffer de 1KB
    loop {
        let n = arquivo.read(&mut buffer)?;
        if n == 0 {
            break; // fim do arquivo
        }
        println!("Lidos {} bytes", n);
    }

    Ok(())
}

Ler com codificação específica

Quando o arquivo não está em UTF-8, use a crate encoding_rs:

Cargo.toml:

[dependencies]
encoding_rs = "0.8"
use std::fs;

fn main() {
    let bytes = fs::read("arquivo_latin1.txt").expect("Erro ao ler");

    // Decodificar de ISO-8859-1 (Latin-1)
    let (texto, _, tinha_erros) = encoding_rs::WINDOWS_1252.decode(&bytes);

    if tinha_erros {
        eprintln!("Aviso: alguns caracteres não puderam ser decodificados");
    }

    println!("Conteúdo: {}", texto);
}

Resumo dos métodos

MétodoQuando usar
fs::read_to_string()Arquivos pequenos de texto
BufReader::lines()Arquivos grandes, leitura linha por linha
fs::read()Arquivos binários
BufReader + read()Arquivos muito grandes, leitura em chunks

Veja também