Reading from binary files

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
Line 25 is bad, bad, bad. The cast is a dead giveaway that you have a problem. Look at line 10 for why.
when i remove it ( char * ) it doesn't compile at all
I use dev-c++ compiler!
Last edited on
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
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.
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
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?
for #1 please
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
}
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??
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.
So i have to make some functions that write/read the string into the file?But what about the other data members?
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.
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?
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.