Lendo do arquivo de texto até que o EOF repita a última linha

O código C ++ a seguir usa um object ifstream para ler inteiros de um arquivo de texto (que tem um número por linha) até atingir o EOF . Por que lê o inteiro na última linha duas vezes? Como consertar isto?

Código:

#include  #include  using namespace std; int main() { ifstream iFile("input.txt"); // input.txt has integers, one per line while (!iFile.eof()) { int x; iFile >> x; cerr << x << endl; } return 0; } 

input.txt :

 10 20 30 

Saída :

 10 20 30 30 

Nota : Eu ignorei todo o código de verificação de erros para manter o snippet de código pequeno. O comportamento acima é visto no Windows (Visual C ++), no cygwin (gcc) e no Linux (gcc).

Apenas siga de perto a cadeia de events.

  • Pegue 10
  • Agarre 20
  • Pegue 30
  • Agarrar EOF

Veja a segunda e última interação. Você pegou 30 e continuou a verificar o EOF. Você não atingiu o EOF porque a marca EOF ainda não foi lida (“binaricamente” falando, sua localização conceitual é logo após a linha 30). Portanto, você continua para a próxima iteração. x ainda é 30 da iteração anterior. Agora você lê o stream e obtém EOF. x permanece 30 e o ios :: eofbit é gerado. Você imprime para stderr x (que é 30, assim como na iteração anterior). Em seguida, você verifica o EOF na condição de loop e, desta vez, está fora do loop.

Tente isto:

 while (true) { int x; iFile >> x; if( iFile.eof() ) break; cerr < < x << endl; } 

Aliás, há outro bug no seu código. Você já tentou executá-lo em um arquivo vazio? O comportamento que você recebe é pelo mesmo motivo.

Eu gosto deste exemplo, que, por enquanto, deixa de fora o cheque que você poderia adicionar dentro do bloco while:

 ifstream iFile("input.txt"); // input.txt has integers, one per line int x; while (iFile >> x) { cerr < < x << endl; } 

Não tenho certeza de como é seguro ...

Há uma abordagem alternativa para isso:

 #include  #include  // ... copy(istream_iterator(iFile), istream_iterator(), ostream_iterator(cerr, "\n")); 

O padrão EOF precisa de uma leitura primária para “autoinicializar” o processo de verificação de EOF. Considere que o arquivo vazio não terá inicialmente seu EOF definido até a primeira leitura. A primeira leitura irá capturar o EOF nesta instância e ignorar completamente o loop.

O que você precisa lembrar aqui é que você não obtém o EOF até a primeira tentativa de ler além dos dados disponíveis do arquivo. A leitura da quantidade exata de dados não sinalizará o EOF.

Gostaria de salientar se o arquivo estava vazio, o código dado teria sido impresso, pois o EOF impedirá que um valor seja definido como x na input do loop.

  • 0

Então, adicione uma leitura primária e mova a leitura do loop para o final:

 int x; iFile >> x; // prime read here while (!iFile.eof()) { cerr < < x << endl; iFile >> x; } 

Sem muitas modificações do código original, poderia se tornar:

 while (!iFile.eof()) { int x; iFile >> x; if (!iFile.eof()) break; cerr < < x << endl; } 

mas eu prefiro as outras duas soluções acima em geral.

 int x; ifile >> x while (!iFile.eof()) { cerr < < x << endl; iFile >> x; } 

No final da última linha, você tem um novo caractere de linha, que não é lido pelo operador >> e não é um final de arquivo. Por favor, faça uma experiência e exclua a nova linha (o último caractere no arquivo) – você não obterá a duplicação. Para ter um código flexível e evitar efeitos indesejados basta aplicar qualquer solução dada por outros usuários.