Pergunta

Recentemente, tive um problema causado pelo uso de fstream :: eof (). Eu li a seguinte linha de aqui :

O eof function () retorna true se o fim do arquivo de entrada associado tenha sido atingido, falso caso contrário.

e (erroneamente) assumiu isso significava que se eu usasse fstream :: read () e ler além do fim do arquivo, o eof function () iria me dizer. Então eu fiz algo assim (muito generalizada):

for(int i = 0; i < max && !file.eof(); i++)
{
     file.read(mything, sizeof(mything));
}

O problema veio por causa do que é explicado mais tarde na página ligada acima (o que eu não leu inicialmente, graças ao primeiro parágrafo enganosa):

Por outro lado, a corrente não entra em estado EOF se acontecer de haver qualquer espaço em branco após a última prova, mas tentando ler outro token ainda falhará. Portanto, a bandeira EOF não pode ser utilizado como um ensaio num circuito destina-se a ler todos os conteúdos de transmissão até EOF. Em vez disso, deve-se verificar a condição falhar após uma tentativa de ler.

Então eu mudei, e agora meus cheques de loop contra file.fail () em vez de file.eof (), e eu entendo como eof () funciona. A minha pergunta é, por que ele funciona dessa maneira? Existem situações em que isso é desejável? Parece-me que uma vez que você passou EOF, você passou EOF e EOF () deve retornar true.

Atualizar Agradecimentos para as respostas, eu acho que eu tenho. A única operação que estou realizando é lido (), e eu imediatamente verificar para fail (), então eu acho que estou bem. Agora, a minha pergunta é, o que se Eu uso eof () para?

Foi útil?

Solução

Por causa desta forma ele pode detectar EOF sem saber o quão grande é o arquivo. Tudo o que tem a fazer é simplesmente tentar ler e se a leitura é curto (mas não um erro), então você chegou ao final do arquivo.

Isso reflete a funcionalidade da chamada de sistema read, que IO arquivo normalmente acaba chamando (coisas win32 pode chamar ReadFile mas acredito que a funcionalidade é similar).

A partir da página de manual read "VALOR DE RETORNO" seção (grifo nosso):

Em caso de sucesso, o número de bytes lidos é devolvido (zero indica o fim do arquivo) , e a posição do arquivo é avançado por este número. Não é uma erro se esse número for menor do que o número de bytes solicitado; isto pode acontecer, por exemplo, porque menos bytes estão realmente disponíveis no momento (Talvez porque estávamos perto EOF, ou porque estamos lendo a partir de um tubo, ou a partir de um terminal), ou porque read () foi interrompido por um sinal. Em caso de erro, -1 é retornado, e errno é ajustado apropriadamente. Nisso caso seja deixado indeterminado se a posição do arquivo (se houver) muda.

BTW: uma boa maneira de escrever o que você queria seria assim:

T something;
while(file.read(something, sizeof(something))) {
    // process your 'something'
}

Isso funciona porque file.read (como muitos membros da iostream) retornar uma referência ao próprio iostream. Todos os que têm um operador sobrecarregado para permitir testar o estado de fluxo. Da mesma forma para ler std::cin, while(std::cin >> x) { ... } funciona tão bem.

EDIT: você deve saber que o teste vs. falha pode ser igualmente errado pela mesma razão. A partir da página é ligada ao fail() retornos se a operação anterior falhou. O que significa que você precisa para realizar uma leitura ou outra operação relevante antes de testá-lo.

Outras dicas

int n;
std::cin >> n >> std::stripws;

corrige esse problema. Nesse ponto, você pode usar qualquer .bom () ou .eof (). Eu gosto de usar .bom (), uma vez que se houver um bloco de disco ruim, .bom () irá detectá-lo. mas isso é comigo. .eof () não vai, você também tem que adicionar .fail () || .bad ().

Eu só descobriu isso depois de algum estudar muito sobre o problema de comer espaço em branco. Eu ia propor uma ECO para iostream e ifstream, e eis que, ele já foi feito. :-D

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top