Reading .txt file

Oct 14, 2009 at 5:30pm
closed account (iA5S216C)
I want to read a .txt file with multiple lines, like this example and output them
in the program (format: Name/Amount of numbers/Numbers):
1
2
3
4
5
Don     2   2 1
Julia   1   8
Robert  0
Maria   5   2 3 9 8 1
James   3   4 5 7


This is an example of my output using my code below:
1
2
3
4
5
6
Don     2   2 1
Julia   1   8
Robert  0
Maria   5   2 3 9 8 1
James   3   4 5 7
James   7   7 7 7 7 7 7 7


As you see it makes an extra line, using the last voornaam and cijfer, but why?
(Hopefully you can read through the dutch names)

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
void toon_teken_voor_teken ( ifstream& infilevar, ofstream& outfilevar )
{
    while ( infilevar )
    {
        char voornaam[7];
        infilevar >> voornaam;
        if ( voornaam )
        {
            cout << voornaam << "\t";
            outfilevar << voornaam << "\t";
            int cijfer, aantal_cijfers;
            infilevar >> cijfer;
            if ( cijfer == 0 )
            {
                cout << cijfer << endl;
            }
            else
            {
                if ( cijfer )
                {
                    aantal_cijfers = cijfer;
                    cout << aantal_cijfers << "\t";
                    outfilevar << aantal_cijfers << "\t";
                }
                for ( int teller = 0 ; teller <= (aantal_cijfers-1) ; teller++ )
                {
                    infilevar >> cijfer;
                    if ( cijfer )
                    {
                        cout << cijfer << " ";
                    }
                }
                cout << endl;
            }
        }
    }
}

int main ()
{
    cout << "Naam\tAantal\tGemiddeld" << endl;
    ifstream leesbestandsvar ("uitslagen.txt");
    ofstream nieuwbestandsvar ("nieuwuitslagen.txt");
    if ( leesbestandsvar )
    {
        toon_teken_voor_teken(leesbestandsvar, nieuwbestandsvar);
    }
    else
    {
        cout << "Leesbestand niet gevonden." << endl;
    }
    return 0;
}
Last edited on Oct 14, 2009 at 5:32pm
Oct 14, 2009 at 5:34pm
Put an empty line at the end of the .txt file. I haven't screwed around with C++ in a while, but I do remember that working at least.
Oct 14, 2009 at 5:36pm
closed account (iA5S216C)
Well since this is for homework, I can't change the file. And it should be universal.
Oct 14, 2009 at 5:38pm
Are you allowed to screw with the file through the program, like with input?

If so, you can just open an ifstream into the file with the ios_base::app option, and add a newline.
Oct 14, 2009 at 6:00pm
closed account (iA5S216C)
No, probably not. Just to read it. But why doesnt my program work/does it make an extra line?
Last edited on Oct 14, 2009 at 6:01pm
Oct 14, 2009 at 6:13pm
Move the while checking after getting input:
1
2
3
4
5
6
while ( true ) // condition moved
{
    char voornaam[7];

    if ( infilevar >> voornaam ) // here
        break; // exit the loop 

Otherwise the last execution of the loop will have an invalid infilevar
Oct 14, 2009 at 6:33pm
closed account (iA5S216C)
Erm if I do that it will only run for the first line [Don 2 2 1].
Oct 14, 2009 at 6:35pm
Sorry, I forgot negation...
if ( !(infilevar >> voornaam) )
Oct 14, 2009 at 6:56pm
closed account (iA5S216C)
Thanks mate, it works now.
But could you explain to me why?
Oct 14, 2009 at 7:05pm
Here is explained what the program does with a simplified version of your code:

1
2
3
4
5
while ( infilevar )
{
    infilevar >> voornaam;
    // ... 
}
while the stream infilevar is good execute the next block

read input - it may fail
do stuff - if input failed it gets executed anyway with odd results
go back to 1


1
2
3
4
5
6
while ( true )
{
    if ( !(infilevar >> voornaam) )
        break;
    // ... 
}
always execute the next block

read input and check for failure - infilevar >> voornaam returns true if after input infilevar is good
if checking failed exit from the while block
do stuff
go back to 1


The only difference between the two version is when you check the file state
Oct 14, 2009 at 7:07pm
The problem is that you execute the entire contents of the loop without regard to the success or failure of attempting to read a voornaam from the file.
1
2
3
4
5
6
7
8
while (infilevar)  // Always true until after an attempt was made to read past EOF
{
  char firstname[7];
  infilevar >> firstname;  // Success or failure happens here

  // Now execute the rest of the loop even though the last input may have failed
  ...
}

The solution is to check for failure after reading but before the rest of the loop.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
while (true)  // It doesn't matter here whether file is good or bad
{
  char firstname[7];

  // Try to get something from the file
  infilevar >> firstname;

  // Now it matters.
  // Check to see if the last attempt to read the file worked or not.
  // If not, then quit the loop.
  if (!infilevar) break;

  // Otherwise we continue with the rest of the loop
  ...
}

Bazzy's code just combined lines 6 and 11 into a single line:
1
2
  // Try to get something from the file. On failure, quit the loop.
  if (!(infilevar >> firstname)) break;

Hope this helps.

[edit] Oops! Sorry Bazzy. I'll go away. :-\
Last edited on Oct 14, 2009 at 7:08pm
Oct 14, 2009 at 7:12pm
closed account (iA5S216C)
Ah now I understand, thank you so much guys !
Topic archived. No new replies allowed.