Capítulo 15: I/O de Alta Performance, Streams e std::filesystem

Especialização em Sistemas com C++ • C++20 & C++23 • RAII, Smart Pointers, Templates, Concorrência e Alta Performance


🗺️ Mapa Conceitual do Subsistema de I/O e Sistema de Arquivos

flowchart TD
    IO["Subsistema de I/O em C++"] --> Filesystem["Manipulação de Arquivos e Pastas (<filesystem>)"]
    IO --> Streams["Fluxos de Dados de Alta Performance (<fstream>)"]

    subgraph FS_OPS["Biblioteca std::filesystem (C++17/C++20)"]
        Path["std::filesystem::path (Portabilidade '/' vs '\\')"]
        DirIter["directory_iterator / recursive_directory_iterator"]
        Meta["Permissões, Tamanho Físico e Espaço Livre em Disco"]
    end

    subgraph STREAM_PERF["Otimizações de Streams"]
        SyncStdio["std::ios_base::sync_with_stdio(false)"]
        BinaryDump["Leitura/Escrita Binária Direta (.read() / .write())"]
        MemoryMapped["Mapeamento em Memória (Memory-Mapped I/O / mmap)"]
    end

    Filesystem --> FS_OPS
    Streams --> STREAM_PERF

    style IO fill:#e1f5fe,stroke:#03a9f4,stroke-width:2px
    style FS_OPS fill:#ede7f6,stroke:#7e57c2,stroke-width:2px
    style STREAM_PERF fill:#e8f5e9,stroke:#4caf50,stroke-width:2px

🏛️ 1. A Padronização com std::filesystem: Portabilidade Sem Dores de Cabeça

Antes da introdução de std::filesystem no C++17 e refinada no C++20, qualquer operação básica com o sistema de arquivos (criar uma pasta recursivamente, verificar existência de arquivo, calcular espaço livre em disco) exigia bibliotecas de terceiros como Boost.Filesystem ou invocações diretas de APIs não portáveis (POSIX no Linux vs Win32 API no Windows).

Com std::filesystem:

  • A classe std::filesystem::path normaliza automaticamente os separadores de diretório (/ no Linux e \ no Windows).
  • O operador / é sobrecarregado para concatenar caminhos de maneira natural: auto arq = dir / "config" / "app.ini";.
  • A manipulação de erros é flexível: métodos aceitam sobrecarga com std::error_code para evitar o lançamento de exceções em rotinas de alta frequência.

⚙️ 2. Navegação em Diretórios e Inspeção de Metadados

A biblioteca simplifica a iteração sobre árvores inteiras de arquivos através de iteradores de range:

#include <filesystem>
#include <iostream>

namespace fs = std::filesystem;

void auditar_diretorio(const fs::path& caminho) {
    if (!fs::exists(caminho)) return;

    for (const auto& entrada : fs::recursive_directory_iterator(caminho)) {
        if (entrada.is_regular_file()) {
            std::cout << "Arquivo: " << entrada.path().filename() 
                      << " | Tamanho: " << entrada.file_size() << " bytes\n";
        }
    }
}

📦 3. Otimizações de I/O em C++: Desativando Sincronizações Inúteis

Em benchmarks de processamento de dados e ingestão de logs, desenvolvedores frequentemente reclamam da lentidão de std::cin e std::cout comparados a scanf/printf. Essa lentidão não é inerente aos streams do C++, mas decorre de uma flag de compatibilidade com o runtime do C clássico que vem ativada por padrão:

// OBRIGATÓRIO em qualquer aplicativo de console de alta performance:
std::ios_base::sync_with_stdio(false); // Desvincula buffers do C++ dos streams do C
std::cin.tie(nullptr);                  // Desassocia flush automático do cin no cout

Leitura e Escrita Binária de Blocos Contíguos:

Para gravar grandes volumes de telemetria ou dados numéricos em disco com performance máxima, nunca formate texto com <<. Utilize gravações em bloco binário com .write():

#include <fstream>
#include <vector>

void gravar_bloco(const std::string& path, const std::vector<float>& dados) {
    std::ofstream arq(path, std::ios::binary);
    // Grava milhões de floats diretamente da memória para o disco com zero conversão
    arq.write(reinterpret_cast<const char*>(dados.data()), dados.size() * sizeof(float));
}

📊 4. Matriz Comparativa: Métodos de Entrada e Saída (I/O)

Abordagem Facilidade de Uso Segurança de Tipos Velocidade de Transferência
Streams Formatados (<<) Altíssima Total Média (sobrecarga de conversão ASCII)
std::ofstream::write() Binário Alta Manual (bytes brutos) Altíssima (próxima à velocidade do NVMe)
I/O Mapeado em Memória (mmap) Média (específica de SO) Manual Velocidade Máxima Teórica (Zero-Copy direto via MMU)
fopen / fwrite do C Baixa Baixa Rápida, mas sem semântica RAII nativa