Por que a simples leitura de arquivo em C++ quebra o código até de experientes?
\n\nImagine a situação: você está escrevendo um parser de configs, logs ou CSV. Tudo parece elementar — abrir o arquivo, ler linha por linha, processar. Mas na realidade, no Stack Overflow a pergunta "Read file line by line using ifstream in C++" acumula milhares de visualizações e centenas de comentários. Por quê? Porque o diabo, como sempre, está nos detalhes.
\n\nNeste artigo, não vamos apenas mostrar como ler um arquivo linha por linha corretamente. Vamos analisar os 5 erros mais comuns e perigosos que transformam código funcional em um monte de bugs. Você vai descobrir por que while (!file.eof()) é um mal, como não perder a última linha e o que fazer com arquivos binários. Vamos lá!
Sintaxe básica: como abrir um arquivo e ler uma linha
\n\nVamos começar com o básico. A classe std::ifstream (input file stream) é sua principal ferramenta para ler arquivos. Aqui está um exemplo funcional mínimo:
#include <iostream>\n#include <fstream>\n#include <string>\n\nint main() {\n std::ifstream file("example.txt");\n std::string line;\n\n if (file.is_open()) {\n while (std::getline(file, line)) {\n std::cout << line << std::endl;\n }\n file.close();\n } else {\n std::cerr << "Erro ao abrir o arquivo!" << std::endl;\n }\n return 0;\n}\n\nParece que algo pode dar errado? E dá.
\n\nErro nº1: Usar while (!file.eof())
\n\nEsta é, provavelmente, a armadilha mais popular para iniciantes. Parece lógico: "enquanto não for o fim do arquivo — leia". Mas o problema é:
\n\n- \n
eof()retornatrueapenas após uma tentativa de leitura mal-sucedida. \n - O loop será executado uma iteração a mais do que o necessário. \n
- A última linha será processada duas vezes ou você receberá dados lixo. \n
Exemplo-catástrofe:
\n\nstd::ifstream file("data.txt");\nstd::string line;\n\nwhile (!file.eof()) { // NUNCA FAÇA ISSO!\n std::getline(file, line);\n std::cout << line << std::endl; // A última linha será exibida duas vezes\n}\n\nSolução correta: use std::getline na condição do loop, como no primeiro exemplo. Ele retorna o próprio fluxo, que é convertido para bool: true se a leitura for bem-sucedida, e false em caso de erro ou fim do arquivo.
Erro nº2: Ignorar a verificação de abertura do arquivo
\n\nParece óbvio, mas milhares de linhas de código no GitHub falham com segmentation fault exatamente por causa disso. Se o arquivo não existir ou não houver permissão de leitura, o ifstream não lançará uma exceção — ele simplesmente ficará em um estado "quebrado".
Incorreto:
\n\nstd::ifstream file("nonexistent.txt");\nstd::string line;\nwhile (std::getline(file, line)) { // Opa! O arquivo não foi aberto\n // Este código nunca será executado\n}\n\nO problema é que você não saberá do erro. Os dados estarão vazios e a lógica do programa será quebrada.
\n\nCorreto:
\n\nstd::ifstream file("data.txt");\nif (!file) {\n std::cerr << "Não foi possível abrir o arquivo!" << std::endl;\n return 1;\n}\n// Em seguida, a leitura\n\nUse if (!file) ou if (!file.is_open()) — não há diferença, ambos verificam o estado do fluxo.
Erro nº3: Esquecer dos espaços e delimitadores
\n\nO operador >> (extração) lê até o primeiro espaço. Se você usá-lo em vez de std::getline, corre o risco de obter algo diferente do esperado.
Exemplo: o arquivo contém a string "Hello World".
std::string word;\nfile >> word; // Lerá apenas "Hello"\n// word == "Hello"