<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() -> std::io::Result<()> {
let conteudo = fs::read_to_string("dados.txt")?;
println!("Conteúdo do arquivo:\n{}", 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() -> std::io::Result<()> {
let arquivo = File::open("grande_arquivo.txt")?;
let leitor = BufReader::new(arquivo);
for (numero, linha) in leitor.lines().enumerate() {
let linha = linha?;
println!("Linha {}: {}", 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() -> std::io::Result<()> {
let bytes = fs::read("imagem.png")?;
println!("Lidos {} bytes", bytes.len());
Ok(())
}</code></pre>
<p>Este método retorna um <code>Vec<u8></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() -> std::io::Result<()> {
let mut arquivo = File::create("saida.txt")?;
arquivo.write_all(b"Olá, Rust!\n")?;
arquivo.write_all(b"Segunda linha.\n")?;
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"string"</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() -> std::io::Result<()> {
let arquivo = File::create("log.txt")?;
let mut escritor = BufWriter::new(arquivo);
for i in 1..=1000 {
writeln!(escritor, "Entrada número: {}", 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() -> std::io::Result<()> {
let mut arquivo = OpenOptions::new()
.append(true)
.open("log.txt")?;
writeln!(arquivo, "Nova entrada")?;
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() -> std::io::Result<()> {
let metadados = fs::metadata("arquivo.txt")?;
println!("Tamanho: {} bytes", metadados.len());
println!("É um arquivo? {}", metadados.is_file());
println!("É um diretório? {}", metadados.is_dir());
println!("Somente leitura? {}", 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() -> std::io::Result<()> {
let bytes_copiados = fs::copy("origem.txt", "destino.txt")?;
println!("Copiados {} bytes", 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>