11

I'm need to know if the next char in ifstream is the end of file. I'm trying to do this with .peek():

if (file.peek() == -1)

and

if (file.peek() == file.eof())

But neither works. There's a way to do this?

Edit: What I'm trying to do is to add a letter to the end of each word in a file. In order to do so I ask if the next char is a punctuation mark, but in this way the last word is left without an extra letter. I'm working just with char, not string.

Tae
  • 1,611
  • 4
  • 24
  • 43
  • 1
    You shouldn't have to. It will not tell you if the next read will fail or not. What are you trying to accomplish? – rubenvb Jun 08 '11 at 18:46
  • What are you trying to achieve that makes you need to know. Maybe if you describe the bigger problem we can suggest how to solve the problem. – Martin York Jun 08 '11 at 18:50
  • 1
    If you really want to test against EOF, try `if (file.peek() == ifstream::traits_type::eof())`. But as littleadv points out, `peek()` will actually set the EOF bit on the stream itself. So as rubenvb points out, what are you trying to do? – Nemo Jun 08 '11 at 18:50

8 Answers8

25

istream::peek() returns the constant EOF (which is not guaranteed to be equal to -1) when it detects end-of-file or error. To check robustly for end-of-file, do this:

int c = file.peek();
if (c == EOF) {
  if (file.eof())
    // end of file
  else
    // error
} else {
  // do something with 'c'
}

You should know that the underlying OS primitive, read(2), only signals EOF when you try to read past the end of the file. Therefore, file.eof() will not be true when you have merely read up to the last character in the file. In other words, file.eof() being false does not mean the next read operation will succeed.

zwol
  • 121,956
  • 33
  • 219
  • 328
  • 13
    In 100% kosher C++, `EOF` is `std::ifstream::traits_type::eof()`. – n. 'pronouns' m. Jun 08 '11 at 19:07
  • 3
    `std::ifstream::traits_type` is `std::char_traits`, and `std::char_traits::eof()` is defined to be `EOF`. C++98 [lib.char.traits.specializations.char]/7. If you were using a wide stream you would need to use `WEOF`, and if you were using `basic_ifstream` with your own traits class you would of course use that class's `eof()`, but I see no reason to bulk up code with references to the traits type when it's not necessary. – zwol Jun 08 '11 at 19:20
8

This should work:

if (file.peek(), file.eof())

But why not just check for errors after making an attempt to read useful data?

Ben Voigt
  • 260,885
  • 36
  • 380
  • 671
2

file.eof() returns a flag value. It is set to TRUE if you can no longer read from file. EOF is not an actual character, it's a marker for the OS. So when you're there - file.eof() should be true.

So, instead of if (file.peek() == file.eof()) you should have if (true == file.eof()) after a read (or peek) to check if you reached the end of file (which is what you're trying to do, if I understand correctly).

littleadv
  • 19,072
  • 2
  • 31
  • 46
2

For a stream connected to the keyboard the eof condition is that I intend to type Ctrl+D/Ctrl+Z during the next input.

peek() is totally unable to see that. :-)

Bo Persson
  • 86,087
  • 31
  • 138
  • 198
1

There is no way of telling if the next character is the end of the file, and trying to do so is one of the commonest errors that new C and C++ programmers make, because there is no end-of-file character in most operating systems. What you can tell is that reading past the current position in a stream will read past the end of file, but this is in general pretty useless information. You should instead test all read operations for success or failure, and act on that status.

1

Usually to check end of file I used:

    if(cin.fail())
    {
        // Do whatever here
    }

Another such way to implement that would be..

    while(!cin.fail())
    {
        // Do whatever here
    }

Additional information would be helpful so we know what you want to do.

tf.rz
  • 1,287
  • 6
  • 17
  • 45
  • @Neil Butterworth - these are snippets of code I used in my university assignments, but mind explaining why they are wrong? ^^ – tf.rz Jun 08 '11 at 18:59
  • @tf You should check the result of each read (and write) operation, as they happen, not the state of the stream BEFORE you do them. –  Jun 08 '11 at 19:03
  • 1
    @tf: Check [this question](http://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-considered-wrong) – Xeo Jun 08 '11 at 19:05
  • They're wrong because `read` (the system call on which iostreams are ultimately built) only signals end-of-file when you try to read *past* the end of the file, not when you read *up to* the end of the file. You probably had an input operation inside that while loop and you didn't bother checking whether it succeeded, and so I could craft input that would break your program. Your instructor should have pointed this out. – zwol Jun 08 '11 at 19:07
  • @Nail Butterworth, Thanks for the enlightenment. @Xeo, thank you for pointing me to that question; it was very helpful. – tf.rz Jun 08 '11 at 19:08
  • @Zack, my instructor didn't really care about how we wrote our programs, as long as they outputted the right things and assigned the right pointers and whatnot. This is why I signed up for stackoverflow. (Y) – tf.rz Jun 08 '11 at 19:09
0

just use this code in macosx

if (true == file.eof())

it work for me in macosx!

lslboy
  • 447
  • 5
  • 12
0

You didn't show any code you are working with, so there is some guessing on my part. You don't usually need low level facilities (like peek()) when working with streams. What you probably interested in is istream_iterator. Here is an example,

  cout << "enter value";

  for(istream_iterator<double> it(cin), end; 
      it != end; ++it)
  {
     cout << "\nyou entered value " << *it;
     cout << "\nTry again ...";
  }

You can also use istreambuf_iterator to work on buffer directly:

  cout << "Please, enter your name: ";

  string name;
  for(istreambuf_iterator<char> it(cin.rdbuf()), end;
    it != end && *it != '\n'; ++it)
  {
    name += *it;
  }
  cout << "\nyour name is " << name;
Gene Bushuyev
  • 5,294
  • 17
  • 19