---
title: "BufReader e BufWriter em Rust"
url: "https://rustlang.com.br/stdlib/bufreader-bufwriter/"
markdown_url: "https://rustlang.com.br/stdlib/bufreader-bufwriter.MD"
description: "Referência completa de BufReader e BufWriter em Rust: I/O bufferizado, lines(), read_line(), with_capacity e impacto na performance."
date: "2026-02-23"
author: "Equipe Rust Brasil"
---

# BufReader e BufWriter em Rust

Referência completa de BufReader e BufWriter em Rust: I/O bufferizado, lines(), read_line(), with_capacity e impacto na performance.


# BufReader e BufWriter em Rust

`BufReader` e `BufWriter` são wrappers que adicionam buffering a qualquer tipo que implemente `Read` ou `Write`, respectivamente. Sem buffering, cada chamada a `read()` ou `write()` resulta em uma syscall ao sistema operacional — o que é extremamente custoso quando feito milhares de vezes com poucos bytes. Com buffering, as operações são agrupadas em blocos maiores, reduzindo drasticamente o número de syscalls.

## Visão geral e tipos-chave

### BufReader<R>

`BufReader<R>` envolve qualquer `R: Read` e mantém um buffer interno (padrão: 8 KB). Além de implementar `Read`, implementa `BufRead`, que fornece métodos como `lines()` e `read_line()`.

### BufWriter<W>

`BufWriter<W>` envolve qualquer `W: Write` e acumula escritas em um buffer interno antes de enviá-las ao destino. O buffer é automaticamente descarregado quando está cheio ou quando `flush()` é chamado.

### Trait BufRead

A trait `BufRead` estende `Read` com acesso ao buffer interno e métodos orientados a linhas:

```rust
pub trait BufRead: Read {
    fn fill_buf(&mut self) -> io::Result<&[u8]>;
    fn consume(&mut self, amt: usize);
    fn read_line(&mut self, buf: &mut String) -> io::Result<usize>;
    fn lines(self) -> Lines<Self>;
    fn split(self, byte: u8) -> Split<Self>;
    fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> io::Result<usize>;
}
```

## Padrões comuns com código

### Leitura linha por linha com BufReader

O padrão mais comum é ler arquivos linha por linha usando `lines()`:

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

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

    for (num, linha) in leitor.lines().enumerate() {
        let linha = linha?; // cada linha pode falhar independentemente
        println!("{:6}: {}", num + 1, linha);
    }

    Ok(())
}
```

### Leitura interativa com read_line

Para leitura incremental (ex: protocolo de rede), use `read_line()`:

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

fn processar_cabecalhos(caminho: &str) -> io::Result<Vec<(String, String)>> {
    let arquivo = File::open(caminho)?;
    let mut leitor = BufReader::new(arquivo);
    let mut cabecalhos = Vec::new();
    let mut linha = String::new();

    loop {
        linha.clear(); // IMPORTANTE: reutilizar o buffer
        let bytes = leitor.read_line(&mut linha)?;

        if bytes == 0 || linha.trim().is_empty() {
            break; // EOF ou linha vazia = fim dos cabeçalhos
        }

        if let Some((chave, valor)) = linha.trim().split_once(':') {
            cabecalhos.push((
                chave.trim().to_string(),
                valor.trim().to_string(),
            ));
        }
    }

    Ok(cabecalhos)
}

fn main() -> io::Result<()> {
    let cabecalhos = processar_cabecalhos("requisicao.txt")?;
    for (chave, valor) in &cabecalhos {
        println!("{}: {}", chave, valor);
    }
    Ok(())
}
```

### Escrita eficiente com BufWriter

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

fn gerar_relatorio(caminho: &str, registros: &[(String, f64)]) -> io::Result<()> {
    let arquivo = File::create(caminho)?;
    let mut escritor = BufWriter::new(arquivo);

    writeln!(escritor, "RELATÓRIO DE VENDAS")?;
    writeln!(escritor, "====================")?;
    writeln!(escritor, "{:<30} {:>12}", "Produto", "Valor (R$)")?;
    writeln!(escritor, "{}", "-".repeat(44))?;

    let mut total = 0.0;
    for (produto, valor) in registros {
        writeln!(escritor, "{:<30} {:>12.2}", produto, valor)?;
        total += valor;
    }

    writeln!(escritor, "{}", "-".repeat(44))?;
    writeln!(escritor, "{:<30} {:>12.2}", "TOTAL", total)?;

    // flush() explícito garante que tudo foi escrito
    escritor.flush()?;
    Ok(())
}

fn main() -> io::Result<()> {
    let vendas = vec![
        ("Notebook Dell".to_string(), 4599.90),
        ("Mouse Logitech".to_string(), 189.50),
        ("Teclado Mecânico".to_string(), 349.00),
        ("Monitor 27 polegadas".to_string(), 1899.00),
    ];
    gerar_relatorio("relatorio.txt", &vendas)?;
    println!("Relatório gerado com sucesso");
    Ok(())
}
```

## Tabela de métodos e funções

### BufReader

| Método | Descrição |
|---|---|
| `BufReader::new(reader)` | Cria com buffer padrão de 8 KB |
| `BufReader::with_capacity(cap, reader)` | Cria com capacidade customizada |
| `buffer()` | Retorna referência ao conteúdo do buffer interno |
| `capacity()` | Retorna a capacidade total do buffer |
| `into_inner()` | Consome o BufReader e retorna o leitor interno |
| `get_ref()` / `get_mut()` | Acesso ao leitor interno por referência |
| `seek_relative(offset)` | Busca relativa sem descartar o buffer |

### BufWriter

| Método | Descrição |
|---|---|
| `BufWriter::new(writer)` | Cria com buffer padrão de 8 KB |
| `BufWriter::with_capacity(cap, writer)` | Cria com capacidade customizada |
| `buffer()` | Retorna referência ao conteúdo não descarregado |
| `capacity()` | Retorna a capacidade total do buffer |
| `into_inner()` | Descarrega e retorna o escritor interno |
| `get_ref()` / `get_mut()` | Acesso ao escritor interno por referência |
| `flush()` | Envia dados bufferizados ao destino |

### BufRead (trait)

| Método | Descrição |
|---|---|
| `lines()` | Iterador sobre linhas (remove `\n` e `\r\n`) |
| `read_line(&mut buf)` | Lê uma linha (inclui `\n`) no buffer |
| `split(byte)` | Iterador que divide por um byte delimitador |
| `read_until(byte, &mut buf)` | Lê até encontrar o byte delimitador |
| `fill_buf()` | Preenche e retorna o buffer interno |
| `consume(n)` | Marca N bytes como consumidos no buffer |

## Exemplos práticos

### Exemplo 1: Processar arquivo CSV grande linha por linha

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

fn analisar_csv(caminho: &str) -> io::Result<()> {
    let arquivo = File::open(caminho)?;
    // Buffer maior para arquivos grandes (64 KB)
    let leitor = BufReader::with_capacity(64 * 1024, arquivo);

    let mut totais_por_categoria: HashMap<String, f64> = HashMap::new();
    let mut linhas_processadas = 0u64;

    for (num, resultado) in leitor.lines().enumerate() {
        let linha = resultado?;

        // Pular cabeçalho
        if num == 0 {
            continue;
        }

        let campos: Vec<&str> = linha.split(',').collect();
        if campos.len() >= 3 {
            let categoria = campos[1].trim().to_string();
            if let Ok(valor) = campos[2].trim().parse::<f64>() {
                *totais_por_categoria.entry(categoria).or_insert(0.0) += valor;
            }
        }
        linhas_processadas += 1;
    }

    println!("Processadas {} linhas", linhas_processadas);
    for (cat, total) in &totais_por_categoria {
        println!("  {}: R$ {:.2}", cat, total);
    }

    Ok(())
}

fn main() {
    if let Err(e) = analisar_csv("vendas.csv") {
        eprintln!("Erro ao processar CSV: {}", e);
    }
}
```

### Exemplo 2: Gerar arquivo grande eficientemente com BufWriter

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

fn gerar_dados_teste(caminho: &str, num_linhas: usize) -> io::Result<()> {
    let arquivo = File::create(caminho)?;
    // Buffer de 128 KB para escrita intensiva
    let mut escritor = BufWriter::with_capacity(128 * 1024, arquivo);

    writeln!(escritor, "id,nome,valor,ativo")?;

    for i in 0..num_linhas {
        writeln!(
            escritor,
            "{},{},{},.{}",
            i,
            format!("item_{:06}", i),
            (i as f64 * 1.5),
            if i % 3 == 0 { "true" } else { "false" }
        )?;
    }

    // into_inner() faz flush automaticamente e retorna o File
    let arquivo_inner = escritor.into_inner().map_err(|e| e.into_error())?;
    let metadata = arquivo_inner.metadata()?;
    println!(
        "Arquivo gerado: {} bytes ({} linhas)",
        metadata.len(),
        num_linhas
    );

    Ok(())
}

fn main() -> io::Result<()> {
    gerar_dados_teste("dados_teste.csv", 1_000_000)?;
    Ok(())
}
```

### Exemplo 3: Dividir entrada por delimitador customizado

```rust
use std::io::{self, BufRead};

fn processar_registros_delimitados(dados: &[u8], delimitador: u8) -> io::Result<Vec<String>> {
    let leitor = io::BufReader::new(dados);
    let mut registros = Vec::new();

    for parte in leitor.split(delimitador) {
        let bytes = parte?;
        let texto = String::from_utf8_lossy(&bytes).to_string();
        if !texto.trim().is_empty() {
            registros.push(texto.trim().to_string());
        }
    }

    Ok(registros)
}

fn main() -> io::Result<()> {
    // Registros separados por '\0' (null byte)
    let dados = b"registro1\0registro2\0registro3\0";
    let registros = processar_registros_delimitados(dados, b'\0')?;
    for (i, reg) in registros.iter().enumerate() {
        println!("[{}] {}", i, reg);
    }

    // Registros separados por '|' (pipe)
    let dados = b"campo_a|campo_b|campo_c|";
    let campos = processar_registros_delimitados(dados, b'|')?;
    println!("Campos: {:?}", campos);

    Ok(())
}
```

### Exemplo 4: Buffer duplo — BufReader + BufWriter para transformação

```rust
use std::fs::File;
use std::io::{self, BufRead, BufReader, BufWriter, Write};

fn converter_formato(
    entrada: &str,
    saida: &str,
    transformar: fn(&str) -> String,
) -> io::Result<(u64, u64)> {
    let leitor = BufReader::new(File::open(entrada)?);
    let mut escritor = BufWriter::new(File::create(saida)?);

    let mut linhas_lidas = 0u64;
    let mut linhas_escritas = 0u64;

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

        let convertida = transformar(&linha);
        if !convertida.is_empty() {
            writeln!(escritor, "{}", convertida)?;
            linhas_escritas += 1;
        }
    }

    escritor.flush()?;
    Ok((linhas_lidas, linhas_escritas))
}

fn main() -> io::Result<()> {
    // Exemplo: remover linhas em branco e converter para maiúsculas
    let (lidas, escritas) = converter_formato(
        "entrada.txt",
        "saida.txt",
        |linha| {
            let trimmed = linha.trim();
            if trimmed.is_empty() {
                String::new()
            } else {
                trimmed.to_uppercase()
            }
        },
    )?;

    println!("Lidas: {}, Escritas: {}", lidas, escritas);
    Ok(())
}
```

## Quando usar buffering e impacto na performance

### Cenário sem buffering (lento)

```rust
use std::fs::File;
use std::io::{self, Write};
use std::time::Instant;

fn sem_buffering() -> io::Result<()> {
    let mut arquivo = File::create("/tmp/sem_buffer.txt")?;
    let inicio = Instant::now();

    // Cada write() = uma syscall ao SO
    for i in 0..100_000 {
        writeln!(arquivo, "Linha {}: dados de exemplo", i)?;
    }

    println!("Sem buffer: {:?}", inicio.elapsed());
    Ok(())
}
```

### Cenário com buffering (rápido)

```rust
use std::fs::File;
use std::io::{self, BufWriter, Write};
use std::time::Instant;

fn com_buffering() -> io::Result<()> {
    let arquivo = File::create("/tmp/com_buffer.txt")?;
    let mut escritor = BufWriter::new(arquivo);
    let inicio = Instant::now();

    // Escritas acumuladas em memória, poucas syscalls
    for i in 0..100_000 {
        writeln!(escritor, "Linha {}: dados de exemplo", i)?;
    }
    escritor.flush()?;

    println!("Com buffer: {:?}", inicio.elapsed());
    Ok(())
}
```

Em testes típicos, a versão com `BufWriter` é **5x a 20x mais rápida** que a versão sem buffering.

### Escolhendo a capacidade do buffer

| Cenário | Capacidade recomendada |
|---|---|
| Uso geral | 8 KB (padrão) |
| Arquivos grandes, leitura sequencial | 64 KB - 256 KB |
| Muitas escritas pequenas | 32 KB - 128 KB |
| Rede com latência alta | 16 KB - 64 KB |
| Arquivos pequenos (< 4 KB) | Não usar buffering |

```rust
use std::io::BufReader;
use std::fs::File;

// Buffer customizado de 256 KB para arquivo grande
let arquivo = File::open("arquivo_grande.dat")?;
let leitor = BufReader::with_capacity(256 * 1024, arquivo);
```

## Padrões de tratamento de erro para I/O

### Cuidado com into_inner() do BufWriter

Ao chamar `into_inner()`, se o flush falhar, o `BufWriter` retorna um `IntoInnerError` que ainda contém o escritor:

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

fn salvar_com_verificacao(caminho: &str, dados: &str) -> io::Result<()> {
    let arquivo = File::create(caminho)?;
    let mut escritor = BufWriter::new(arquivo);
    escritor.write_all(dados.as_bytes())?;

    match escritor.into_inner() {
        Ok(_arquivo) => {
            println!("Dados salvos com sucesso");
            Ok(())
        }
        Err(erro) => {
            eprintln!("Erro ao descarregar buffer: {}", erro.error());
            // erro.into_inner() recupera o BufWriter para tentar novamente
            Err(erro.into_error())
        }
    }
}
```

### BufWriter faz flush no Drop, mas ignora erros

Quando um `BufWriter` sai de escopo, ele tenta fazer flush dos dados restantes. Porém, se o flush falhar, o erro é silenciosamente ignorado. Sempre chame `flush()` ou `into_inner()` explicitamente em código de produção.

## Veja também

- [Módulo std::io](/stdlib/io-module/) — visão geral das traits e tipos de I/O
- [Read e Write Traits](/stdlib/read-write/) — as traits fundamentais de I/O
- [File e OpenOptions](/stdlib/file/) — abrir e criar arquivos
- [Ler Arquivo em Rust](/receitas/ler-arquivo/) — receita prática de leitura com BufReader
- [Ler Arquivo CSV](/receitas/ler-csv/) — processamento de CSV linha por linha
- Documentação oficial: [`BufReader`](https://doc.rust-lang.org/std/io/struct.BufReader.html), [`BufWriter`](https://doc.rust-lang.org/std/io/struct.BufWriter.html)
