Reading from binary files

Jan 16, 2010 at 7:13pm
hello everyone.I have written this piece of code
in order to practise myself in files.
I have come up a weird problem though and
i would like your help.In the statement

iof.open("A File1", ios_base :: in | ios_base :: binary);

as soon as i remove ios_base :: in the program works fine
it reads the contents of the file.But when i have it there the program
crashes when it reaches the statement cout << smth.str << endl;


Can anyone give me an idea of wht's going wrong?


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
#include <iostream>
#include <fstream>
#include <string>
#include <ctime>
using namespace std;


struct sss
{
    string str;
    int age;
    char *date;
};
    
    
int main()
{
    
    time_t sec;
    time(&sec);
    sss smth = {"denis", 19, ctime(&sec)};
    fstream iof;
    iof.clear();
    iof.open("A File1", ios_base :: in | ios_base :: binary);
    iof.read((char *) &smth, sizeof smth);
    cout << smth.str << endl;
    cout << smth.age << endl;
    cout << smth.date << endl;
    iof.close();
    iof.clear();
    iof.open("A File1", ios_base :: out | ios_base :: app | ios_base :: binary);
    iof.write((char *) &smth, sizeof smth);
    iof.close();
    
    system("pause");
    return 1;
}
Last edited on Jan 16, 2010 at 7:14pm
Jan 16, 2010 at 7:42pm
Line 25 is bad, bad, bad. The cast is a dead giveaway that you have a problem. Look at line 10 for why.
Jan 16, 2010 at 7:48pm
when i remove it ( char * ) it doesn't compile at all
I use dev-c++ compiler!
Last edited on Jan 16, 2010 at 7:49pm
Jan 16, 2010 at 7:56pm
Waitaminnit. You're casting string to char*? Just do .c_str()!
And dev is outdated, use wxdev.
EDIT: You aren't just casting string to char, you're casting a reference to a class... you realize how disastrous that is considering that the compiler doesn't know how to perform that conversion?
Last edited on Jan 16, 2010 at 7:56pm
Jan 16, 2010 at 8:07pm
afaik you can't read directly to a string like this. Using c_str() on line 25 won't do you any good.

In order to have a string in a binary file, you need to have some way to determine where the end of the string is. Some common ways are:

1) Null terminate the string (IE: a 0 marks the end of the string)
2) Put the length of the string before the actual string data. IE: 4,'t','e','s','t'. The 4 indicates there's 4 characters in the string
3) Only use a fixed length for the string. IE always have 20 characters saved to the file, no matter how long the string actually is.


How you read/write the string depends on which of the above methods you employ.

As for which of the above is "better", it depends on the situation. #1 is hardest to deal with for file I/O but is the most flexible, whereas #3 is the most restrictive, but possibly the easiest to work with. #2 is somewhere in between.
Jan 16, 2010 at 8:12pm
I have written in a book about write() and read() functions
and the syntax was the same.

if that's the case can anyone tell me other function that is appropriate for writing struct or classes into file?
Last edited on Jan 16, 2010 at 8:16pm
Jan 16, 2010 at 8:18pm
It depends how you want the string stored in the file.

I can give you sample code, but the code depends on how it's stored.

Which of the above options do you want?
Jan 16, 2010 at 8:24pm
for #1 please
Jan 16, 2010 at 8:44pm
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
string ReadNullTermString(istream& file)
{
    string s;  // the string to read
    char c;

    while(file.good())   // check for unexpected EOF / error
    {
        c = file.get();
        if(!c)      // null found
            break;  // so break out of the loop

        s += c;
    }

    return s;
}

void WriteNullTermString(ostream& file,string s)
{
    // note this only works if 's' does not contain any null characters
    //   which I don't explicitly check for, since it'll probably never happen
    //   If you need to have strings that contain nulls for whatever reason, you
    //   will not be able to use this method of storing strings.  You'll probably have
    //   to go with option #2

    file.write( s.c_str(), s.length() );  // write the string
    file.put(0);                          // put the null terminator at the end
}
Jan 17, 2010 at 9:37pm
that's ok.But what if we had a class instead of struct with the same data members.
How could we write the class into the file??
Jan 17, 2010 at 9:45pm
That's a tough topic. Typically you define a text format that can represent the data well, either a fixed format or a delimited one. You need to write formatters and parsers. This can be done within an override of the stream input and stream output operators.

You could also use Boost Serialize, but that's not really something a beginner would use.
Jan 17, 2010 at 9:53pm
So i have to make some functions that write/read the string into the file?But what about the other data members?
Jan 17, 2010 at 10:32pm
Yes, you have to write out all data members. You have a std::string, an integer, and a C string (char*). All three must be written to the file so that you can read them back into the same structure. You cannot write out integers directly because they have different sizes and different endianness on different systems.

The easiest way to do this is to write out each member per line, that way you know you must read in three lines to fill the structure.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
ostream& operator<<(ostream& os, const sss& s)
{
    os << s.str << endl << s.age << endl << s.date << endl;
    return os;
}

istream& operator>>(istream& is, sss& s)
{
    getline(is, s.str);
    string input;
    getline(is, input);
    istringstream in(input);
    in >> input;
    getline(is, input);
    // Here we assume that s.date has been allocated...
    strcpy(s.date, input.c_str());
    return is;
}


Note that there is no error checking in this -- it must be added. Note the comment. It is important that s.date has a buffer allocated for it *before* reading the file. It really should be another std::string rather than a C string.
Jan 18, 2010 at 5:20pm
i don't understand the lines:

1
2
3
4
5
string input;
getline(is, input);
istringstream in(input);
in >> input;
getline(is, input);


can you explain me what you are doing?
Jan 18, 2010 at 7:04pm
Sorry -- that was a mistake. Line 13 (line 4 in your most recent post) should say "in >> s.age;".
Topic archived. No new replies allowed.