Binary File Input not reaching EOF

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    cop=1;//DEV
    while(database.good())//FIXME
        {
            database.read(buf, 21);

            if(database.eof()) //*1
                break;

            for(int i=0; i<7; i++)
                {
                    if(cop==3)//DEV *2
                        buf[0]='k';

                    cout<<&buf[i*3];database.tellg();
                }
            cop++;//DEV
            cout<<endl;
        }


this file contains multiple entrances of 7*(3char string).

Cop is there because I was getting one more output from the file than I'd expect.

Output without "if *2" and without "if *1" is:
1
2
3
4
CDEFGAB
CDEFGAB
CDEFGAB
CDEFGAB


My file only has the first three outputs.

so when I add "if *2" output looks like this:

1
2
3
4
CDEFGAB
CDEFGAB
kDEFGAB
kDEFGAB


which means that output three is not coming from the file but from a residue of buf. Also if a cout<<tellg() after each database.read() then the 4th it runs tellg==-1.

If I add "if 1*" the program runs like expected, my question is shouldn't the while condition deal with this? because if not I'd be better of with a while(1) and the "if 1*".

What do you guys think?

EDIT: typos

EDIT2: Also the fact that I'm atempting to read after the EOF seems to turn on the bad flag, and therefore I can't write anything after I do so. How can I fix this?
Last edited on
You can do this:
1
2
3
4
5
6
fstream File ("somefile.txt");
int c;
while((c = File.get()), c != EOF)
{
  //do stuff with char(c)
}


@Edit2: .clear() will help you ;)
I've got data in the file other than chars.. So I supose reading a char at a time isn't the best alternative...

And performance wise doesn't seem like a good idea is it?
You could try coding it like this:
1
2
3
4
while(database.read(buf, 21))
{
    // in here the read was successful
}


This may be helpful:
http://www.parashift.com/c++-faq-lite/input-output.html

And perhaps particularly:
http://www.parashift.com/c++-faq-lite/input-output.html#faq-15.5
Last edited on
I've gone through that faq, but well changing the code to what you said doe nothing. It has the same effect as this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    cop=1;//DEV
    while(database.good())//FIXME
        {
            database.read(buf, 21);

            for(int i=0; i<7; i++)
                {
                    if(cop==3)//DEV *2
                        buf[0]='k';

                    cout<<&buf[i*3];database.tellg();
                }
            cop++;//DEV
            cout<<endl;
        }


The problem here is that the eof is only set after reading file_size+1 bytes. And the last time database.read(buf, 21); it doesn't change the value of buf because it's already at file_size bytes and there's nothing else to read.

This is not my main problem as I can solve this with an if statement. The problem is that once it tries to read past eof the bad flag is raised.

Unenabling me to write to file after that happens, which I need to.

Here's what I need to do:

1.-input some info.

2.-read file to check if that info is already in it.

3.-if info is not on file, then write it to file.

Everything is running smothly except for the 3rd step, which fails because of the erro flag not letting me write to file.

Hope that helps..

btw: I was thinking I could first check file size and read only that number of bytes. But what's upsetting me is that this seems like a C++ implementation problem and not my fault...

EDIT: Heres the code if it helps:

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
void Scale::write_scale()
{
    if(!open_file())
        {
            cout<<"Cannot write scale to disk.\n";
            return;
        }

    char buf[22];
    int cop;


    while(database.good())//FIXME
        {
            cop=1;

            database.read(buf, 21);

            if(database.eof())
                break;

            for(int i=0; i<7; i++)
                {
                    if(strcmp(&buf[i*3],&scl[i*3])!=0)
                        {
                            cop=0;
                            break;
                        }
                }

            if(cop==1)
                {
                    cout<<"That scale is already in the database.\n";
                    return;
                }

        }

    database.seekp(0, ios::end);

    cout<<"tellp: "<<database.tellp()<<endl;

    for(int i=0; i< scl_notes_n; i++)
        {
            database.write(&scl[i*3],3);
        }

    database.close();
}


cout<<"tellp: "<<database.tellp()<<endl; -> this outputs -1
Last edited on
I am still not sure what exactly you are trying to do but it seems that you are reading and writing to the same file? You can clear any error flags (like eof) using std::stream::clear()
 
database.clear(); // now you can continue reading/writing 

You might find std::istream::readsome() useful too:
1
2
3
4
5
6
7
8
char buf[21];
std::streamsize len;

while((len = database.readsom(buf, 21)) == 21)
{
    // buf successfully read all 21 chars
}
// number of chars read into buf contained in len 
readsome(buf,21) didn't work.

But clear() did the trick.

Thanks,

Hugo Ribeira
Topic archived. No new replies allowed.