Por que ifstream.eof () não retorna TRUE depois de ler a última linha de um arquivo?

11

Quando um iniciante começa a ler os fluxos de if, seu instinto é ler o arquivo usando um loop que geralmente se parece com isso:

while (!ifstream.eof()
{
...
}

No entanto, quando usei esse código, notei que ele não parava até ter lido a última linha do arquivo duas vezes. Os programadores de C ++ observam que não é assim que se deve ler um arquivo. Em vez disso, eles geralmente recomendam que quem precisa ler um arquivo use um loop como este:

while (ifstream >> someVar)
{
...
}

Por que o primeiro trecho de código sempre falha ao funcionar corretamente?

moonman239
fonte
Eu teria pensado que haveria uma duplicata, mas não consigo encontrar uma aqui. Há muitas duplicatas no stackoverflow.
David Hammen

Respostas:

4

o while (!ifstream.eof()) loop não funciona, porque os fluxos / arquivos em C e C ++ não prevêem quando você atingiu o final do arquivo, mas indicam se você tentou ler além do final do arquivo.

Se a última linha do arquivo terminar com um \ncaractere newline ( ), a maioria das ações de leitura interromperá a leitura quando o encontrarem e não detectarem que esse é o último caractere do arquivo. Na próxima ação de leitura, pode até ser que mais caracteres tenham sido anexados e que a leitura tenha sucesso em extraí-los.

O loop que usa o operador de extração de fluxo ( while (ifstream >> someVar)) funciona porque o resultado do operador de extração de fluxo foi avaliado como falso se não pudesse extrair um item do tipo certo. Isso também acontece se não houver caracteres para ler.

Bart van Ingen Schenau
fonte
4

No entanto, os programadores de C ++ observam que o que sempre acontece é que cin.eof () não retorna "true" até que a última linha tenha sido lida duas vezes.

Não é isso que está acontecendo. Ele eofbitnão desempenha nenhum papel na conversão para um booleano ( stream::operator bool(ou operator void*em c ++ mais antigo)). Somente o badbite failbitestão envolvidos.

Suponha que você esteja lendo um arquivo contendo números separados por espaços em branco. Um loop baseado cin.eof()inevitavelmente estará errado ou cheio de iftestes. Você não está lendo até EOF. Você está lendo números. Portanto, faça seu código expressar essa lógica:

while (stream >> some_var) {
    process_value(some_var);
}

Isso funcionará se a última linha do arquivo terminar com 0 42\nou apenas 0 42(nenhuma nova linha no final da última linha do arquivo). Se o arquivo terminar com 0 42\n, a última boa leitura recuperará o valor 42 e lerá o marcador final de linha final. Observe que o marcador EOF ainda não foi lido. A função process_valueé chamada com 42. A próxima chamada para o operador de extração de fluxo >> lê o EOF e, como nada foi extraído, ambos eofbite failbitserão definidos.

Suponha, por outro lado, que o arquivo termine com 0 42(nenhuma nova linha no final da última linha). A última boa leitura recuperará o valor 42 terminando no marcador EOF. Presumivelmente, você deseja processar esses 42. É por isso eofbitque não desempenha um papel no operador de conversão booleana do fluxo de entrada. Na próxima chamada para o operador de extração de fluxo >>, o mecanismo subjacente vê rapidamente que eofbitjá está definido. Isso resulta rapidamente na configuração de failbit.

Por que o primeiro trecho de código sempre falha ao funcionar corretamente?

Porque você não deve verificar EOF como a condição do loop. A condição do loop deve expressar o que você está tentando fazer, que é (por exemplo), extrair números de um fluxo.

David Hammen
fonte