Podo
Podo

Reputation: 709

Searching for char from end of file using seekg() c++

I have a file and I want to only output the last line to the console.

Here's my thoughts on how I would do it. Use file.seekg(0, ios::end) to put myself at the end of file.

Then, I could create a decrement variable int decrement = -1; and use a while loop

 while (joke.peek() != '\n')
 {
     decrement--;

 }

and get the starting position for my final line (going backwards from the end).

Knowing this, joke.seekg(decrement, ios::end); should set me to the beginning of the final line, and assuming I previously declared string input; I would think that

 getline(joke, input);
 cout << input << endl;

would output it to the console.

Full code

 void displayLastLine(ifstream &joke)
 {
    string input;
    int decrement = -1;


    joke.clear();
    joke.seekg(0, ios::end);


    while (joke.peek() != '\n')
    {
        decrement--;

    }
    joke.clear();

    joke.seekg(decrement, ios::end);

    getline(joke, input);
    cout << input << endl;

}

The problem is, when I go to call this method for the file, nothing happens. When I step through it, the decrement just keeps on subtracting one, far beyond where a '\n' would be. To give an example of a text file, it would look something like this:

junk

garbage

skip this line

This is the line that we're looking for!

Upvotes: 0

Views: 2407

Answers (3)

Duly Kinsky
Duly Kinsky

Reputation: 996

Your loop is actually only decrementing "decrement" and not using it to make the next search.

while (joke.peek() != '\n')

{
    joke.seekg(decrement, std::ios::end);
    decrement--;
}

Upvotes: 0

luk32
luk32

Reputation: 16070

peek does not move the file pointer, it reads the character without extracting it. So, you are constantly peeking the same value (character) and ending up in an infinite loop.

What would you need to do is something like:

while (joke.peek() != '\n')
{
    joke.seek(-1, ios::cur);
}

That would put the input position at the \n, using the 2nd overload of seekg.

Please note that this is not a perfect solution. You need to check for errors and boundary conditions, but it explains your observed behaviour and gives you something to start fixing your code.

Upvotes: 1

Sam Varshavchik
Sam Varshavchik

Reputation: 118340

joke.seekg(0, ios::end);

This positions the file at the end.

while (joke.peek() != '\n')

Well, here's problem #1. When you're at the end of the file, peek() always returns EOF.

    decrement--;

You write:

When I step through it, the decrement just keeps on subtracting one,

Well, what did you expect to happen, since that's the only thing that the loop does? The only thing your for loop does is subtract 1 from decrement. So that's what happens.

This a common problem: a computer does only what you tell it to do, instead of what you want it to do.

Although this is not optimal, your missing step is that before you peek(), you need to seek() back by one character. Then, peek() shows you the character at the current cursor position. Then, seek() back by one more character, and check peek() again, and so on.

But that still will not be sufficient for you. Most text files end with a newline character. That is, a newline is the last character in the file. So, even if you add back the missing seek(), in nearly all cases, what your code will end up doing is finding the last character in the file, the final newline character.

My recommendation for you is to stop writing code for a moment, and, instead, come up with a logical process for doing what you want to do, and describe this process in plain words. Then, discuss your proposed course of action with your rubber duck. Only after your rubber duck agrees that what you propose will work, then translate your plain language description into code.

Upvotes: 1

Related Questions