how write a structure instance to file and then read it?

Pages: 12
i have these code for write an instance of a structure and then read it:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
struct user
{
    string name;
    image foto; //my class image for images
    string adress;
    int age;
};

user usrName;
user usrName2;
usrName.adress="viseu";
    usrName.age=23;
    usrName.name="joaquim";
    usrName.foto.FileName="C:\\Nova pasta\\acrobat.bmp";
    
    FILE* f = fopen("C:\\Nova pasta\\username1.dat", "w+b");
    if(f==NULL)
        DebugText("error");
    fwrite(&usrName, sizeof( user), 1, f);
    fseek(f, 0, SEEK_SET);
    fread(&usrName2, sizeof(user), 1, f);
    fclose(f);
fb.Text=usrName2.name;//i get it without problems 

when i end the program, sometimes, the OS system give me an error(that stops responding) and then close the aplication).
why these happens?
user is not a POD type. Treating it as a buffer (for example, by passing a pointer to it to a function that accepts raw memory) is unsafe. The state of usrName2 after line 21 is undefined, because the internal pointers held by the std::string members have been corrupted.
but i get the string correctly.
what is a POD type?
how can i save the usrName directly on file(without doing a member by member)?
Last edited on
but i get the string correctly.
Like I said, the state is undefined. You probably got the right string because you saved and restored the pointers within the same run of the program. If you try to restore first, you'll probably crash immediately when you try to read the string.
But still, since the behavior is undefined, anything can happen.

what is a POD type?
Basically, a POD type is a basic type (integer, floating point, or pointer), an array of PODs, or a struct that only contains other PODs as members.

how can i save the usrName directly on file(without doing a member by member)?
If you want to use std::strings, you can't.
It can work if you replace the std::strings with char arrays of constant length.
Last edited on
the image class isn't POD, but seems works now that i change from string to char*
but my image class use strings too
Last edited on
seems works now that i change from string to char*
Note that I said char arrays. As in
1
2
3
struct A{
    char text[size];
};


but my image class use strings too
You have to change the image as well, of course.
i'm sorry, but can i do a way for accept strings? even add a string external member or something?(think on what i mean)
You can't directly serialize complex objects. There are whole projects dedicated to solving this problem in maintainable ways. These projects are generators that accept their own type description languages and output C++ code that implements the types described in the input and the corresponding de/serialization routines.

https://developers.google.com/protocol-buffers/
http://avro.apache.org/docs/1.4.0/api/cpp/html/
https://github.com/Helios-vmg/cppserialization (Shameless self-promotion.)
i'm sorry, but can i do a serialization general?(compatible with diferent class's)
What do you mean?
Just bite the bullet and write the code. It isn't that hard if you create methods specifically for reading and writing:
1
2
3
4
5
6
7
8
9
struct user
{
    string name;
    image foto; //my class image for images
    string adress;
    int age;
    bool write(FILE *fp);
    bool read(FILE *fp);
};
dhayden my problem is other: the write() and read() will be only for user.
the write() and read() can be compatible with other structures?
the write() and read() can be compatible with other structures?
No, you will have to write your own riting/reading functions for each structure.

In absence of reflection mechanism, generic object serialization/deserialization is one of the most complex tasks you can imagine in C++.

I would suggest to use text-based files and do not touch binary files. They aren't needed often.

As far as possible, avoid palooka stuff like this:
1
2
bool write(FILE *fp);
bool read(FILE *fp);


1. Strongly favour C++ streams (they handle user-defined types elegantly) over C streams.

2. Use a textual representation for the persisted information: for instance, one field per line
(we should be able to write a file on one machine, take the file to another machine, and read it there).

Note: If you are forced (say, by the archetypical 'teacher') to use patently inferior techniques, at the very least make it const-correct.
1
2
bool write(FILE *fp) const ;
bool read(FILE *fp);


I would suggest something along these lines:

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
#include <iostream>
#include <string>
#include <sstream>

struct image
{
    std::string file_name ;
};

////////////////////// implement  i/o functionality for image (image can take care of itself) ///////////
std::ostream& operator<< ( std::ostream& stm, const image& img ) 
{ return stm << img.file_name << '\n' ; } // add more lines if image has more information

std::istream& operator>> ( std::istream& stm, image& img )
{ return std::getline( stm, img.file_name ) ; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////

struct user
{
    std::string name;
    image foto; //my class image for images
    std::string address;
    int age;
};

////////////////////////////////  implement  i/o functionality for user //////////////////////////////////
std::ostream& operator<< ( std::ostream& stm, const user& usr ) // one member per line, extra newline at end
{ return stm << usr.name << '\n' << usr.foto << usr.address << '\n' << usr.age << "\n\n" ; }

std::istream& operator>> ( std::istream& stm, user& usr )
{
    while( std::getline( stm, usr.name ) && usr.name.empty() ) ; // skip leading empty lines
    stm >> usr.foto && std::getline( stm, usr.address ) && stm >> usr.age ;
    if( !stm || usr.age < 0 ) { usr = {} ; stm.clear(std::ios_base::failbit) ; }
    return stm ;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////

int main() // simple test program
{
    constexpr std::size_t N = 3 ;
    std::stringstream file ;

    {
        const user users[N] {
                                { "joaquim", { "C:\\Nova pasta\\acrobat.bmp" }, "viseu", 23 },
                                { "yakim", { "C:\\Nova pasta\\gymnast.bmp" }, "leiria", 7 },
                                { "loakim", { "C:\\Nova pasta\\funambulist.bmp" }, "guarda", 86 }
                            };

        for( const auto& a_user : users ) file << a_user << '\n' ;
    }

    {
        std::cout << "the following were read back from stream:\n-----------------\n\n" ;
        int cnt = 0 ;
        user some_user ;
        while( file >> some_user ) std::cout << '#' << ++cnt << ".\n" << some_user << '\n' ;
    }
}

http://coliru.stacked-crooked.com/a/5688859e707df967
seems that i found a little about the problem. i don't belive that it's from write\read the file. but my image class have a HBITMAP variable member. and isn't POD. how can i fix that?
> but my image class have a HBITMAP variable member. and isn't POD. how can i fix that?

Do not read or write the value of the member with opaque type HBITMAP.

Instead, read/write the file name, and recreate the bitmap from file (to get the HBITMAP) on input.
but these code is for be used like database, imagine if the image file ins't on other pc?
Then you have to also include the bitmap (that is, the pixel values, plus dimensions, plus any other required metadata) somehow.
Last edited on
someone advice me for overload the ifstream& operator>>()... maybe tomorrow i will do it and correct it.
i'm trying averloading it:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
friend ofstream& operator << (ofstream &os, const image &img2)
    {
        int stringsize=img2.strfilename.size()+1;
        char chrFileName[img2.strfilename.size()+1];
        sprintf(chrFileName,"%s",img2.strfilename.c_str());
        os << stringsize << chrFileName;
        return os;
    }

    friend ifstream& operator >> (ifstream &is, image &img2)
    {
        DebugText("reading file");//i don't get these message
        int stringsize;
        is >>stringsize;
        char chFileName[stringsize];
        is >>chFileName;
        img2.readimagefile(chFileName);
        DebugText("end of reading file");//i don't get these message 
        return is;
    }

(i'm doing these on my image class)
like you see i'm just trying save the string file name. but why these code is never called?
Pages: 12