Rust

Leitura e Escrita de Arquivos em Rust com std::fs: Do Básico ao Avançado

9 min de leitura

Leitura e Escrita de Arquivos em Rust com std::fs: Do Básico ao Avançado

Introdução ao Módulo std::fs O módulo (filesystem) é a porta de entrada para manipulação de arquivos em Rust. Ele fornece uma API segura e eficiente para criar, ler, escrever e manipular arquivos no sistema operacional. Diferentemente de linguagens como Python ou JavaScript, Rust força o desenvolvedor a lidar explicitamente com erros através do tipo , tornando o tratamento de exceções de I/O obrigatório e previsível. Antes de começar, saiba que todo arquivo em Rust precisa ser aberto, lido/escrito e então fechado. O bom é que Rust fecha automaticamente os arquivos quando saem do escopo, graças ao trait . Isso significa menos vazamento de recursos comparado a linguagens menos seguras. Leitura de Arquivos Leitura Simples com readtostring A forma mais direta de ler um arquivo inteiro é usar . Este método é ideal quando seu arquivo cabe na memória: O operador desempacota o automaticamente. Se houver erro, a função retorna o erro imediatamente. Isso é muito mais limpo que verificar explicitamente

<h2>Introdução ao Módulo std::fs</h2>

<p>O módulo <code>std::fs</code> (filesystem) é a porta de entrada para manipulação de arquivos em Rust. Ele fornece uma API segura e eficiente para criar, ler, escrever e manipular arquivos no sistema operacional. Diferentemente de linguagens como Python ou JavaScript, Rust força o desenvolvedor a lidar explicitamente com erros através do tipo <code>Result</code>, tornando o tratamento de exceções de I/O obrigatório e previsível.</p>

<p>Antes de começar, saiba que todo arquivo em Rust precisa ser aberto, lido/escrito e então fechado. O bom é que Rust fecha automaticamente os arquivos quando saem do escopo, graças ao trait <code>Drop</code>. Isso significa menos vazamento de recursos comparado a linguagens menos seguras.</p>

<h2>Leitura de Arquivos</h2>

<h3>Leitura Simples com read_to_string</h3>

<p>A forma mais direta de ler um arquivo inteiro é usar <code>std::fs::read_to_string</code>. Este método é ideal quando seu arquivo cabe na memória:</p>

<pre><code class="language-rust">use std::fs;

fn main() -&gt; std::io::Result&lt;()&gt; {

let conteudo = fs::read_to_string(&quot;dados.txt&quot;)?;

println!(&quot;Conteúdo do arquivo:\n{}&quot;, conteudo);

Ok(())

}</code></pre>

<p>O operador <code>?</code> desempacota o <code>Result</code> automaticamente. Se houver erro, a função retorna o erro imediatamente. Isso é muito mais limpo que verificar explicitamente <code>match</code> em cada operação.</p>

<h3>Leitura em Chunks com BufReader</h3>

<p>Para arquivos grandes, ler tudo de uma vez é ineficiente. Use <code>BufReader</code> para processar linha por linha:</p>

<pre><code class="language-rust">use std::fs::File;

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

fn main() -&gt; std::io::Result&lt;()&gt; {

let arquivo = File::open(&quot;grande_arquivo.txt&quot;)?;

let leitor = BufReader::new(arquivo);

for (numero, linha) in leitor.lines().enumerate() {

let linha = linha?;

println!(&quot;Linha {}: {}&quot;, numero + 1, linha);

}

Ok(())

}</code></pre>

<p>Esta abordagem usa buffering interno, reduzindo chamadas ao sistema operacional. Cada linha é processada sob demanda, economizando memória mesmo com arquivos de gigabytes.</p>

<h3>Leitura Binária</h3>

<p>Para arquivos binários, use <code>read</code> ao invés de <code>read_to_string</code>:</p>

<pre><code class="language-rust">use std::fs;

fn main() -&gt; std::io::Result&lt;()&gt; {

let bytes = fs::read(&quot;imagem.png&quot;)?;

println!(&quot;Lidos {} bytes&quot;, bytes.len());

Ok(())

}</code></pre>

<p>Este método retorna um <code>Vec&lt;u8&gt;</code>, permitindo processar dados binários como você precisar.</p>

<h2>Escrita de Arquivos</h2>

<h3>Escrita Simples com write_all</h3>

<p>Para escrever conteúdo de uma vez, use <code>File::create</code> combinado com <code>write_all</code>:</p>

<pre><code class="language-rust">use std::fs::File;

use std::io::Write;

fn main() -&gt; std::io::Result&lt;()&gt; {

let mut arquivo = File::create(&quot;saida.txt&quot;)?;

arquivo.write_all(b&quot;Olá, Rust!\n&quot;)?;

arquivo.write_all(b&quot;Segunda linha.\n&quot;)?;

Ok(())

}</code></pre>

<p>Observe que <code>arquivo</code> deve ser mutável (<code>mut</code>). O método <code>write_all</code> garante que todos os bytes sejam escritos, retornando erro se alguma coisa falhar. Note que estamos usando literais de byte (<code>b&quot;string&quot;</code>), não strings Unicode diretas.</p>

<h3>Escrita com BufWriter</h3>

<p>Para múltiplas operações de escrita, <code>BufWriter</code> melhora a performance através de buffering:</p>

<pre><code class="language-rust">use std::fs::File;

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

fn main() -&gt; std::io::Result&lt;()&gt; {

let arquivo = File::create(&quot;log.txt&quot;)?;

let mut escritor = BufWriter::new(arquivo);

for i in 1..=1000 {

writeln!(escritor, &quot;Entrada número: {}&quot;, i)?;

}

escritor.flush()?; // força a escrita do buffer

Ok(())

}</code></pre>

<p>O <code>writeln!</code> é uma macro que escreve com quebra de linha. Note o <code>flush()</code> no final — sem isso, dados podem permanecer no buffer e não serem persistidos em disco imediatamente.</p>

<h3>Append (Adicionar ao Final)</h3>

<p>Para adicionar conteúdo ao final de um arquivo existente, use <code>OpenOptions</code>:</p>

<pre><code class="language-rust">use std::fs::OpenOptions;

use std::io::Write;

fn main() -&gt; std::io::Result&lt;()&gt; {

let mut arquivo = OpenOptions::new()

.append(true)

.open(&quot;log.txt&quot;)?;

writeln!(arquivo, &quot;Nova entrada&quot;)?;

Ok(())

}</code></pre>

<p>Se o arquivo não existir, <code>OpenOptions::append</code> falhará. Para criar se não existir, adicione <code>.create(true)</code>.</p>

<h2>Manipulação Avançada</h2>

<h3>Metadados e Verificações</h3>

<p>Antes de processar um arquivo, você pode querer verificar seu tamanho ou existência:</p>

<pre><code class="language-rust">use std::fs;

fn main() -&gt; std::io::Result&lt;()&gt; {

let metadados = fs::metadata(&quot;arquivo.txt&quot;)?;

println!(&quot;Tamanho: {} bytes&quot;, metadados.len());

println!(&quot;É um arquivo? {}&quot;, metadados.is_file());

println!(&quot;É um diretório? {}&quot;, metadados.is_dir());

println!(&quot;Somente leitura? {}&quot;, metadados.permissions().readonly());

Ok(())

}</code></pre>

<p>Este padrão é essencial para validar argumentos antes de operações custosas.</p>

<h3>Cópia Eficiente de Arquivos</h3>

<p>Rust oferece <code>copy</code> que delega ao sistema operacional quando possível:</p>

<pre><code class="language-rust">use std::fs;

fn main() -&gt; std::io::Result&lt;()&gt; {

let bytes_copiados = fs::copy(&quot;origem.txt&quot;, &quot;destino.txt&quot;)?;

println!(&quot;Copiados {} bytes&quot;, bytes_copiados);

Ok(())

}</code></pre>

<p>Esta função é mais eficiente que ler e escrever manualmente, especialmente para arquivos grandes.</p>

<h2>Conclusão</h2>

<p>Você aprendeu que o módulo <code>std::fs</code> de Rust combina <strong>segurança</strong> (através de <code>Result</code> obrigatório), <strong>eficiência</strong> (via buffering e gerenciamento automático de recursos) e <strong>simplicidade</strong> (com uma API intuitiva). Os padrões principais são: use <code>read_to_string</code> para leitura simples, <code>BufReader</code> para grandes arquivos, e <code>BufWriter</code> para múltiplas escritas. Sempre trate erros com o operador <code>?</code> e lembre-se de que <code>mut</code> é necessário para escrita.</p>

<p>Na prática, a maioria dos programas Rust que lidam com I/O seguem esses padrões. Domine-os e você terá uma vantagem significativa em projetos reais.</p>

<h2>Referências</h2>

<ul>

<li><a href="https://doc.rust-lang.org/std/fs/" target="_blank" rel="noopener noreferrer">Documentação Oficial std::fs</a></li>

<li><a href="https://doc.rust-lang.org/book/ch12-00-an-io-project.html" target="_blank" rel="noopener noreferrer">The Rust Book - Chapter 12: I/O Project</a></li>

<li><a href="https://doc.rust-lang.org/rust-by-example/std_misc/file.html" target="_blank" rel="noopener noreferrer">Rust by Example - File I/O</a></li>

<li><a href="https://doc.rust-lang.org/std/io/struct.BufReader.html" target="_blank" rel="noopener noreferrer">std::io::BufReader Documentation</a></li>

<li><a href="https://doc.rust-lang.org/error_codes/E0106.html" target="_blank" rel="noopener noreferrer">Common Rust Lifetime Mistakes - Error Handling Patterns</a></li>

</ul>

Comentários

Mais em Rust

Como Usar Enums em Rust: Definição, Variantes e Dados Associados em Produção
Como Usar Enums em Rust: Definição, Variantes e Dados Associados em Produção

Introdução: O Que São Enums em Rust? Enums (enumerações) são um dos pilares d...

Guia Completo de Criando Tipos de Erro Customizados em Rust
Guia Completo de Criando Tipos de Erro Customizados em Rust

Por que Customizar Tipos de Erro em Rust? Em Rust, tratamento de erros é uma...

O que Todo Dev Deve Saber sobre Biblioteca anyhow: Tratamento de Erros em Aplicações Rust
O que Todo Dev Deve Saber sobre Biblioteca anyhow: Tratamento de Erros em Aplicações Rust

Por Que Tratamento de Erros em Rust é Diferente Em Rust, erros não são exceçõ...