Using ifstream to grab text and output it to the console

Hello and thanks for the help.
I was watching the video in the link below which did a decent job of helping me to learn what I'm doing, but at times he glosses over things and doesn't mention necessary steps which can leave many lost. I linked it directly to the necessary time by the way.
https://www.youtube.com/watch?v=Rub-JsjMhWY#t=37m25s

In this case I'm wondering why my console (Visual Studio 2013) outputs a random character continuously. His code did look suspiciously disjointed, but I'm wondering how to make my code use the .get() function to successfully output the characters in my text file
Please Note:
The output is the same whether or not I use the .close() function on each of the ofstream and ifstream sections or not. I'm confused.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <iostream>
#include <fstream>
using namespace std;

int main()
{
	ofstream writer("respo.txt");
	{
		if (!writer)
		{
			cout << "Error" << endl;
		}
		writer << "Hi, My name is Jeff" << endl;
		writer << "Hi, My name is Tom" << endl;
		cin.get();
	}

	{
		if (!writer)
		{
			cout << "Error" << endl;
		}

		writer << "Hi, My name is Pam" << endl;
		writer << "Hi, My name is Saint" << endl;
		cin.get();
	}

	ofstream writer2("respo.txt", ios::app);
	{
		if (!writer2)
		{
			cout << "Error" << endl;
		}

		writer2 << "Hi, My name is Jessie" << endl;
		writer2 << "Hi, My name is Surly" << endl;
		cin.get();
	}

	
	char letter;

	ifstream reader("repo.txt");

	for (int i = 0; !reader.eof(); i++)
	{
		reader.get(letter);
		cout << letter;
	}
	reader.close();
	cin.get();
}



Thank you again!
There are a couple of problems here. One is that there is no check to see whether or not reader was opened successfully.
1
2
3
4
5
6
    ifstream reader("repo.txt");
    if (!reader)
    {
        cout << "Error opening reader" << endl;
        cin.get();
    }


Second, you provided a pretty good example of why it is bad practice (as well as a logic error) to use eof() as the condition of a loop. First, if there was some other error, nothing is ever read from the file, so the eof() can never be true, hence it loops forever.

Here an example using for convenience a stringstream instead of a file, to show the logic error:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>

using namespace std;

int main()
{
    char letter;
       
    istringstream reader("apple");
                
    while (!reader.eof())
    {
        reader.get(letter);
        cout << letter;
    }
    
    cout << '\n';
    
    istringstream read2("orange");
           
    while (read2.get(letter))
    {    
        cout << letter;
    }
        
    cin.get();
}


Output:
applee
orange


Notice an extra 'e' has appeared at the end of apple in the output. Can you see where that has come from?

One more comment, if you are intending to use the same filename throughout, such as "respo.txt", it is better to declare that as a string at the start,
const string filename = "respo.txt";
or perhaps const char* filename = "respo.txt";

Also, you should usually make sure the file was closed after writing, before re-opening for further access.
Last edited on
Effect of closing the file:
Compare this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>
#include <fstream>

using namespace std;

int main()
{    
    const char* filename = "respo.txt";     
 
    ofstream writer(filename);
    {
        if (!writer)
        {
            cout << "Error writer" << endl;
        }
        writer << "Hi, My name is Jeff\n"
               << "Hi, My name is Tom\n"
               << "Hi, My name is Pam\n"
               << "Hi, My name is Saint\n";
    }
    
    char letter;

    ifstream reader(filename);

    while (reader.get(letter) )
    {
        cout << letter;
    }
    
    cout << "\nDone\n";
    cin.get();      
}

Output:

Done


with this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>
#include <fstream>

using namespace std;

int main()
{    
    const char* filename = "respo.txt";     
 
    {
        ofstream writer(filename);
        if (!writer)
        {
            cout << "Error writer" << endl;
        }
        writer << "Hi, My name is Jeff\n"
               << "Hi, My name is Tom\n"
               << "Hi, My name is Pam\n"
               << "Hi, My name is Saint\n";
    }
    
    char letter;

    ifstream reader(filename);

    while (reader.get(letter) )
    {
        cout << letter;
    }
    
    cout << "\nDone\n";
    cin.get();    
}

Output:
Hi, My name is Jeff
Hi, My name is Tom
Hi, My name is Pam
Hi, My name is Saint

Done


Hint: only lines 10 and 11 have changed.
Last edited on
Wow. Thanks so much for the clear explanation, Chervil.

One more comment, if you are intending to use the same filename throughout, such as "respo.txt", it is better to declare that as a string at the start,
const string filename = "respo.txt";
or perhaps const char* filename = "respo.txt";

Also, you should usually make sure the file was closed after writing, before re-opening for further access.


This particular particular bit of advice was perfect. I made a silly mistake in the first code and typed reader("repo.txt"); instead of reader("respo.txt");. When i implanted your solution it worked perfectly and highlighted where I made my mistake.
Interestingly, though, I didn't have to close it, which is very odd. Why is it always recommended that you close text files? I'm hoping I don't run into a huge issue in the future.

I also am not quite sure where "applee" came from, but I'm still very, very new to this. I wouldn't want to take up more of your time if you're busy.

Thanks so much for helping me.
Interestingly, though, I didn't have to close it, which is very odd. Why is it always recommended that you close text files? I'm hoping I don't run into a huge issue in the future.

The difference in my code was that I just used '\n' to output a newline character at the end of each line. In your code you used endl. The difference is that endl first sends the '\n' and then flushes the buffer, that is, it forces it to be physically sent to the hard drive. Mostly we don't want to do this with disk files, it can lead to lots of unnecessary disk activity. Instead we let the system automatically send the contents of the buffer to the disk whenever it is full, and when the file is closed.

Closing the file also frees up the resources and makes them available for use elsewhere. In the case of abnormal program termination, files which are not properly closed may lead to data loss.

I also am not quite sure where "applee" came from, but I'm still very, very new to this. I wouldn't want to take up more of your time if you're busy.

To understand this you need to grasp two things:
• how a loop works
• when is the eof() flag set

So, considering this piece of code:
1
2
3
4
5
6
7
    istringstream reader("apple");
                
    while (!reader.eof())
    {
        reader.get(letter);
        cout << letter;
    }

At the start, the first time we get to line 3, it is not end of file so the body of the loop is entered. At line 5 a character is read and displayed at line 6.

Then control goes back to the top of the loop. The condition is tested: is it eof? No, so the process repeats for each letter.

When we get to line 5 and get the last letter, everything is still ok, the character is read successfully, it hasn't yet hit the end of file. So the letter 'e' is output and control goes back to line 3. Is it eof? No. So the body of the loop is entered one more time. At line 5, the get() will fail, and the eof flag is set. We proceed to line 6, output the existing character stored in letter. That's another 'e'. Next, we go back to the start of the loop, test eof(), find it is true, and quit the loop.

Hope that makes some kind of sense, sometimes fairly simply ideas can seem complicated when written down. Anyway, time spent learning the basics is well spent, it can save hours of pain later.

Note, we could fix the code like this:
1
2
3
4
5
6
7
8
    istringstream reader("apple");
           
    reader.get(letter);     
    while (!reader.eof())
    {
        cout << letter;
        reader.get(letter);
    }
...but that means the get() has to be done in two different places.

It's better to just put the get() (or other input operation) inside the loop condition as I did with the 'orange' example.
Last edited on
The difference in my code was that I just used '\n' to output a newline character at the end of each line. In your code you used endl. The difference is that endl first sends the '\n' and then flushes the buffer, that is, it forces it to be physically sent to the hard drive. Mostly we don't want to do this with disk files, it can lead to lots of unnecessary disk activity. Instead we let the system automatically send the contents of the buffer to the disk whenever it is full, and when the file is closed.

Closing the file also frees up the resources and makes them available for use elsewhere. In the case of abnormal program termination, files which are not properly closed may lead to data loss.
Oh Wow. I remember reading about the differences between "\n" and "endl" some time ago and had no understanding of what it meant. Okay, now I have an understanding of its practical application. That's really cool. I guess I'll try to use them when appropriate if their eventual outputs can indeed be different and affect the length of my code in the memory buffer.


At the start, the first time we get to line 3, it is not end of file so the body of the loop is entered. At line 5 a character is read and displayed at line 6.

Then control goes back to the top of the loop. The condition is tested: is it eof? No, so the process repeats for each letter.

When we get to line 5 and get the last letter, everything is still ok, the character is read successfully, it hasn't yet hit the end of file. So the letter 'e' is output and control goes back to line 3. Is it eof? No. So the body of the loop is entered one more time. At line 5, the get() will fail, and the eof flag is set. We proceed to line 6, output the existing character stored in letter. That's another 'e'. Next, we go back to the start of the loop, test eof(), find it is true, and quit the loop.

Hope that makes some kind of sense, sometimes fairly simply ideas can seem complicated when written down. Anyway, time spent learning the basics is well spent, it can save hours of pain later.
Indeed it does make quite a bit of sense although, I'm not advanced enough yet to truly grasp the totality of why. I think, however, I have a general idea because there have been times where I've had to output the first value for some variables outside of for loops then raise my starting value by one within the loop in order to receive the proper output. I'm kind of associating this with that.


It's better to just put the get() (or other input operation) inside the loop condition as I did with the 'orange' example.
I'm going to do a bit of the leg work myself in order to test the code and try to get a full understanding of the concept. Thanks for being so willing to help and taking the time to explain these things to me. Hopefully I can work my way up to becoming more advanced in the near future.
You're welcome. We covered several different topics there, it's easy to become overwhelmed trying to take in too much at once. Don't worry if it doesn't all make sense at first.
Topic archived. No new replies allowed.