Problems with files in c++

Can someone help me? There are problems in void write() and void update() after the first if.

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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
#include<iostream>
#include<fstream>
#include<string>
using namespace std;
void read();
void write();
void update();
int main()
{
    read();
    write();
    update();

}
void read()
{
    ofstream f;
    int itemnumber,availability,n;
    string author,title;
    f.open("file.txt");
    cout<<"Enter number of books: ";
    cin>>n;
    for(int i=0;i<n;i++)
    {
        cout<<"Enter item number: ";
        cin>>itemnumber;
        cin.get();
        cout<<"Enter title: ";
        getline(cin,title);
        cout<<"Enter author: ";
        getline(cin,author);
        cout<<"Enter availability:";
        cin>>availability;
        f<<itemnumber<<" "<<title<<", "<<author<<", "<<availability<<endl;
    }
    f.close();
}
void write()
{
    ifstream f;
    int itemnumber,availability;
    string author,title;
    f.open("file.txt");
    while(!f.eof())
    {
        f>>itemnumber;
        getline(f,title,',');
        getline(f,author,',');
        f>>availability;
        cout<<itemnumber<<" "<<title<<" "<<author<<" "<<availability<<endl;
    }
    f.close();
}
void update()
{
    ifstream f;
    ofstream t;
    int itemnumber,availability,choose;
    string author,title,searching;
    f.open("file.txt");
    t.open("temp.txt");
    cout<<"Enter title for search: ";
    cin.get();
    getline(cin,searching,',');
    while(!f.eof())
    {
        f>>itemnumber;
        f.get();
        getline(f,title,',');
        f.get();
        getline(f,author,',');
        f>>availability;
        if(searching==title)
         {cout<<"Enter 0 for renting and 1 for returning ";
          cin>>choose;
          if(choose==0)
            availability --;
          if(choose==1)
            availability ++;
          else
            cout<<"Invalid choice "; break;
         }
         else
            cout<<"There isnt a book with this name "; break;
        t<<itemnumber<<" "<<title<<", "<<author<<", "<<availability<<endl;
    }
    t.close();
    f.close();
    ifstream d;
    ofstream a;
    d.open("temp.txt");
    a.open("file.txt");
    while(!t.eof());
    {
        d>>itemnumber;
        getline(d,title,',');
        getline(d,author,',');
        d>>availability;
        a<<itemnumber<<" "<<title<<", "<<author<<", "<<availability<<endl;
    }

}
Last edited on
describe one of these problems
First of all, in the write() function the console doubled the last thing. Then in the update() function after the first if the console is waiting to enter something but I cant input nothing.
First of all, in the write() function the console doubled the last thing.

That is a common symptom of using eof() in the loop condition. That is wrong for a number of reasons, mainly that you need to check the file status after reading from it, not before. In this case, the input fails, so it simply displays the existing contents of the variables.

Here, an alternative version of your write() function. I named it input()

(I find your function naming confusing, because the write() function is reading from the file, and the read() function is writing to the file).

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
void input()
{
    ifstream fin("file.txt");
    
    int itemnumber;
    int availability;
    string author;
    string title;
    string line;
    
    while (getline(fin, line))
    {
        istringstream f(line);
        
        f >> itemnumber; 
        f.ignore();
        
        getline(f,title,','); 
        f.ignore();
        
        getline(f,author,',');
        f >> availability;
        if (f)
            cout << itemnumber << " " << title << " " << author << " " << availability << endl;
    }
    fin.close();
}


It requires the header #include<sstream> because it reads the file a whole line at a time, then uses a stringstream to parse the contents of that line. There are other ways of doing this, but this way makes the file access simple.

Above, at line 11, the body of the loop is entered only after successfully reading a line from the file. Then at line 13, a stringstream is created. It can be accessed in exactly the same way as a file, but contains only the current line. Importantly, at line 23, if (f) the status of the stringstream is checked (again in the same way as we would check a file) and the output is printed only if the status is good, i.e. the values were properly extracted from the line.
Last edited on
Thank you so much! And two more questions can you explain me the meaning of ifstream fin() and istringstream f(line) because I'm a student and a beginner and we haven't studied about these yet and finally do you have any ideas about my second problem?
can you explain me the meaning of ifstream fin() and istringstream f(line)
 
    ifstream fin("file.txt");
is the usual way of declaring and opening an input file.

I often see students write code such as
1
2
    ifstream fin;
    fin.open("file.txt");

which gives the same outcome but is more long-winded, especially if there are other intervening statements between the two lines.

It possibly may have something to do with the way you are being taught, which often seems to be influenced by older styles of programming in the C language, rather than modern C++.

See constructor and open for ifstream
http://www.cplusplus.com/reference/fstream/ifstream/ifstream/
http://www.cplusplus.com/reference/fstream/ifstream/open/


Much the same with the istringstream, I declared and initialised it in a single statement. Consider it as a bit like declaring an integer
 
    int x = 5;
rather than
1
2
    int x;
    x = 5;

There's a reference page for istringstream too
http://www.cplusplus.com/reference/sstream/istringstream/
and finally do you have any ideas about my second problem?

I can take a guess. You have getline() and formatted input cin >> used together in the same program.

This often causes difficulty. The problem is, getline reads everything up until it finds a newline character '\n', which it reads and discards. cin >> just reads the required value, but doesn't bother about any following newline character, so it sits there in the input buffer until later, when a getline finds it and reads an empty string.

The solution? After a statement such as
 
    cin>>availability;
there will be a trailing newline left in the input buffer. You can remove it right away with a statement such as cin.ignore() or commonly, something of the style of cin.ignore(1000, '\n'). The second version reads and ignores up to 1000 characters, or until a newline is reached.

Then the input buffer is clear and ready for the next input, whatever it may be.
It's probably worth having a version without stringstream. Only minor changes between this and earlier version. Mainly, file f is used rather than stringstream f. And line 12:
 
    while ( f >> itemnumber  )

This means, while an item number has been read from the file, enter the loop body and read the other values. Still being cautions, the check at line 21 is there as before, ensuring the output is produced only when the file access was successful.

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
void input()
{
    ifstream f("file.txt");
    
    int itemnumber;
    int availability;
    string author;
    string title;

    string line;
    
    while ( f >> itemnumber  )
    {
        f.ignore();
        
        getline(f,title,','); 
        f.ignore();
        
        getline(f,author,',');
        f >> availability;
        if (f)
            cout << itemnumber << " " << title << " " << author << " " << availability << endl;
    }
    f.close();
}

Last edited on
Thank you so much!!!
Chervil I tried your solution for the problem in void update() but it doesn't work, can you suggest me something else?
I wasn't following the code closely. I just noticed in update(),

 
    getline(cin,searching,',');


I found that unusual, it uses the comma as a delimiter. More commonly we would omit the delimiter, and hence use the default which is the newline character '\n'.

Is that what you intended to do?
When I write the file I put commas after the author and the title in order to read them to the commas after then you can see in write() and read() functions.
That isn't quite the question I was asking. I'm aware of the format you use to store the information in the file.

However, you were asking about a problem, quote,
"Then in the update() function after the first if the console is waiting to enter something but I cant input nothing. "
which I presumed meant you could not enter the book title. Did you mean something else? Could you give the specific line or lines of code which are causing you a problem, I'm rather lost here.
I think that the program doesn't work after line 76
There are a number of logic errors or problems in that whole section of code.
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
    getline(cin,searching,',');
    while(!f.eof())
    {
        f>>itemnumber;
        f.get();
        getline(f,title,',');
        f.get();
        getline(f,author,',');
        f>>availability;
        if(searching==title)
         {cout<<"Enter 0 for renting and 1 for returning ";
          cin>>choose;
          if(choose==0)
            availability --;
          if(choose==1)
            availability ++;
          else
            cout<<"Invalid choice "; break;
         }
         else
            cout<<"There isnt a book with this name "; break;
        t<<itemnumber<<" "<<title<<", "<<author<<", "<<availability<<endl;
    }


Line 64: Use of comma in getline is quirky and may confuse the user. The end-user of a program should not be concerned with the details of how the data is stored. Just use
 
    getline(cin, searching);


Line 65: use of eof() in a loop condition is not good practice - already discussed.

Line 78: if(choose==1) you should use else if here, otherwise if the user chooses 0, it isn't 1 and the message "Invalid choice " will be output, even though 0 is valid.

Line 81. The break; statement is not part of that if/else. It means that the loop will stop reading from the file as soon as the (searching==title) finds a match. In other circumstances that might be ok. But here you need to read and write the entire file, regardless of whether the item is found.

Line 83/84: The message "There isnt a book with this name " will be output if the search doesn't find the book on the first attempt. That message cannot be determined until the entire file has been read, therefore it should be printed after the loop is completed. Set a bool flag if the book is found, and test it afterwards.

Line 84: The break; statement is not part of any if condition at all. It means the while loop will end after the first iteration.


Out of interest, this was my version of the update() function. I used separate functions for read and write of a single record from the file, as they are called from multiple places throughout the program and offer several advantages, one of which is that the file format is guaranteed to be the same, no matter which part of the program is accessing it.

Note the use of the bool found flag. Also note there are no break statements.
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 update()
{
    ifstream f("file.txt");
    ofstream t("temp.txt");
    
    int itemnumber;
    int availability;
    int choose;
    
    string author;
    string title;
    string searching;

    cout << "Enter title for search: ";

    getline(cin, searching);

    bool found = false;

    while (readRecord(f, itemnumber, availability, author, title) )    
    {
        if (searching == title)
        {
            found = true;
            
            cout << "Enter 0 for renting and 1 for returning ";
            cin >> choose;
            if (choose == 0)
                availability --;
            else if (choose == 1)
                availability ++;
            else
                cout << "Invalid choice "; 
        }

        writeRecord(t, itemnumber, availability, author, title); 
    }

    if (!found)
        cout << "There isnt a book with this name "; 

    t.close();
    f.close();
    
    //------------------------------
    
    ifstream d("temp.txt");
    ofstream a("file.txt");
    
    while (readRecord(d, itemnumber, availability, author, title) )  
        writeRecord(a, itemnumber, availability, author, title);  

}

Thank you but can you tell me which library to use with write/readRecord
And can you give me an alternative way to write

while (readRecord(d, itemnumber, availability, author, title) )
writeRecord(a, itemnumber, availability, author, title);

with

d>>itemnumber;
getline(d,title,',');
getline(d,author,',');
d>>availability;
a<<itemnumber<<" "<<title<<", "<<author<<", "<<availability<<endl;
Last edited on
There are no other libraries needed. You write the code for the function yourself.
You could write the header like this:
1
2
ifstream & readRecord(ifstream & is, int & itemnumber, int & availability, 
        string & author, string & title)
Notice the parameters are passed by reference as they will be modified. The value to be returned is simply the stream is.

Alternatively, you don't have to use that function, just adapt the code from the earlier post:
http://www.cplusplus.com/forum/beginner/224747/#msg1028001


(or if you choose to write the separate function, refer to the same post mentioned here).
Last edited on
I made it to this

1
2
3
4
5
6
7
8
9
10
11
while(d>>itemnumber);
    {
        d.get();
        getline(d,title,',');
        d.get();
        getline(d,author,',');
        d>>availability;
        a<<itemnumber<<" "<<title<<", "<<author<<", "<<availability<<endl;
    }
    d.close();
    a.close();

but somehow it doest work well
It looks like during the copy+paste a semicolon mysteriously appeared at the end of the first line while(d>>itemnumber);
I found my mistake and it is the ; after the while
Topic archived. No new replies allowed.