Lendo e escrevendo arquivos em Rust 1.x: abordagens de facto

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Rust e arquivos: mitos, medos e abordagens de facto

Você já se perguntou: "Qual é a maneira correta de ler e escrever arquivos no Rust moderno?". Se sim, você não está sozinho. No Stack Overflow, a pergunta "What's the de-facto way of reading and writing files in Rust 1.x?" acumulou milhares de visualizações e dezenas de respostas. Esta é uma verdadeira dor para a comunidade, especialmente para aqueles que vêm do Python ou JavaScript, onde open() e read() são o básico, e no Rust é preciso lidar com ownership, borrowing e uma série de traits.

Neste artigo, vamos detalhar todas as principais formas de trabalhar com arquivos em Rust 1.x: desde "apenas ler tudo para uma string" até a leitura eficiente linha por linha de grandes logs. Você aprenderá qual abordagem é considerada idiomática e qual é melhor guardar para casos especiais. Vamos lá!



1. std::fs: arsenal padrão

O módulo std::fs é sua primeira parada. Ele fornece funções para ler, escrever, copiar e excluir arquivos. O Rust 1.x estabilizou wrappers convenientes que ocultam a maior parte do trabalho de baixo nível com chamadas de sistema.



Lendo o arquivo inteiro para uma string

A maneira mais simples é usar std::fs::read_to_string. Ele abre o arquivo, lê todo o seu conteúdo para a memória e retorna um Result<String>. Ideal para pequenos arquivos de configuração ou arquivos de texto.

use std::fs;

fn main() -> std::io::Result<()> { let content = fs::read_to_string("hello.txt")?; println!("O arquivo contém:{}", content); Ok(())}

Esta forma é o padrão de facto para casos simples. É concisa, segura e usa ? para tratamento de erros. A única desvantagem é que o arquivo inteiro é carregado na memória, portanto, não é adequado para logs de gigabytes.



Lendo para um vetor de bytes

Se você estiver trabalhando com dados binários (imagens, arquivos), use std::fs::read. Ele retorna um Vec<u8>.

use std::fs;

fn main() -> std::io::Result<()> { let bytes = fs::read("image.png")?; println!("Lidos {} bytes", bytes.len()); Ok(())}


Escrevendo em um arquivo

Para escrever, use std::fs::write. Ele aceita um caminho e dados (string ou array de bytes) e cria/substitui o arquivo.

use std::fs;

fn main() -> std::io::Result<()> { fs::write("output.txt", "Olá, Rust!")?; Ok(())}

Simples como dois mais dois. Mas se você precisar anexar ao final do arquivo, em vez de sobrescrevê-lo, terá que usar OpenOptions.



2. BufReader e BufWriter: quando o tamanho importa

Para arquivos grandes ou operações frequentes de E/S, os wrappers com buffer vêm em socorro. Eles reduzem o número de chamadas de sistema, o que é crítico para o desempenho.



Leitura linha por linha com BufReader

O exemplo clássico é ler um arquivo de log grande linha por linha:

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

fn main() -> std::io::Result<()> { let file = File::open("large_log.txt")?; let reader = BufReader::new(file);

for line in reader.lines() { let line = line?; println!("{}", line); } Ok(())}

O método lines() retorna um iterador de linhas, cada uma sendo um Result<String>. Observe o line? dentro do loop — é o tratamento de erros de leitura de cada linha.

Importante: lines() remove os caracteres de nova linha. Se você precisar mantê-los, use read_until ou leia o arquivo como Vec<u8>.



Escrevendo com BufWriter

Ao escrever grandes volumes de dados, o buffer também é útil:

use std::fs::File;use std::io::{BufWriter, Write};

fn main() -> std::io::Result<

Blogs

Book Recommendations