Thread: read / write binary files

  1. #1
    Darkness Prevails Dark_Phoenix's Avatar
    Join Date
    Oct 2006
    Location
    Houston, Texas
    Posts
    174

    read / write binary files

    I have two questions with reading / writing complex data in a binary file. I have this code which saves a complex type (struct) in a binary file.
    Code:
    #include <iostream>
    #include <string>
    #include <fstream>
     
    struct DATA
    {
        std::string  s1;
        std::string  s2;
        int          i1;
        int          i2;
        std::string  s3;
        double       d1;
        double       d2;
        std::string  s4;
    };
     
    void Save(DATA &d)
    {
        std::ofstream oFile("data.bin", std::ios::out | std::ios::binary);
        oFile.write( (char*)&d, sizeof(d) );
        oFile.close();
        return;
    }
     
    void Load(DATA &d)
    {
        std::ifstream iFile("data.bin", std::ios::in | std::ios::binary);
        iFile.read( (char*)&d, sizeof(d) );
        iFile.close();
        return;
    }
     
    void Display(DATA &d)
    {
        std::cout<<"string 1  = " <<d.s1 <<"\n"
                 <<"string 2  = " <<d.s2 <<"\n"
                 <<"integer 1 = " <<d.i1 <<"\n"
                 <<"integer 2 = " <<d.i2 <<"\n"
                 <<"string 3  = " <<d.s3 <<"\n"
                 <<"double 1  = " <<d.d1 <<"\n"
                 <<"double 2  = " <<d.d2 <<"\n"
                 <<"string 4  = " <<d.s4 <<"\n\n\n\n";
        return;
    }
     
    int main()
    {
        DATA x, y;
        x.s1 = "This is some text";
        x.s2 = "This is some more text";
        x.i1 = 5;
        x.i2 = 55423;
        x.s3 = "And some more text";
        x.d1 = 87.12;
        x.d2 = 1123.542;
        x.s4 = "Wait! Here's some more text!!";
        Display(x);
        Save(x);
        Load(y);
        Display(y);
        return 0;
    }
    #1 : How does the system know the correct size of DATA for the calls to read() and write()? My understading is the objects of type std::string can have a different size depending on the data that it contains.

    #2 : Is this legal / safe?
    Last edited by Dark_Phoenix; 06-21-2009 at 04:21 AM.
    Using Code::Blocks and Windows XP

    In every hero, there COULD be a villain!

  2. #2
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    What you are doing is not legal. You are essentially storing the internal data parts of string class, which IS NOT the string itself. Most of the time, the string will be stored as a pointer to the actual string data. So you'd be storing the pointer. When the data is being read back, you read back the pointer again. If you do this after destroying the original string (or after restarting the application), the pointer will no longer point to the value of the original string.

    You supply the size of d to read/write, so that's how it knows (but of course, sizeof(std::string) will be something like 8 or 16, no matter if you have a single character or 500 characters in the string. Becuase the string class itself doesn't store the whole string - only a pointer to strings.

    If you want to do this as a binary file, you have two choices:
    1. Make it a POD structure - that is, do not use anything that is a class in the storage structure.
    2. Use serialization - produce a pair input/output functions that stores the individual components in a form that you can read back reliably.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  3. #3
    Darkness Prevails Dark_Phoenix's Avatar
    Join Date
    Oct 2006
    Location
    Houston, Texas
    Posts
    174
    Thanks. serialization is what I have been doing when working with std::strings, was just playing around with some ideas. I had a feeling that this would not work right, just did not quite understand what was going on "behind the scenes".

    Just so that I understand correct.... If I were to change the std::strings to char arrays, then this would work?
    Using Code::Blocks and Windows XP

    In every hero, there COULD be a villain!

  4. #4
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by Dark_Phoenix View Post
    Just so that I understand correct.... If I were to change the std::strings to char arrays, then this would work?
    Indeed. But they need to be proper arrays, not dynamic arrays using pointers.

    By the way, if you split your test-program so that it exits after save, and then loads in a second process, you will see that it doesn't work, even if your current example appears to work.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  5. #5
    Darkness Prevails Dark_Phoenix's Avatar
    Join Date
    Oct 2006
    Location
    Houston, Texas
    Posts
    174
    OK, I got it... I split my test pogram like you suggested and I see what you mean. So now I have
    Code:
    struct DATA
    {
        char    s1[30];
        char    s2[30];
        int     i1;
        int     i2;
        char    s3[30];
        double  d1;
        double  d2;
        char    s4[30];
    };
    
    int main()
    {
        DATA x, y;
    
        strcpy_s(x.s1, sizeof(x.s1), "This is some text");
        strcpy_s(x.s2, sizeof(x.s2), "This is some more text");
        x.i1 = 5;
        x.i2 = 55423;
        strcpy_s(x.s3, sizeof(x.s3), "And some more text");
        x.d1 = 87.12;
        x.d2 = 1123.542;
        strcpy_s(x.s4, sizeof(x.s4), "Wait! Here's some more text!!");
    
        Display(x);
        Save(x);
        Load(y);
        Display(y);
    
        return 0;
    }
    And this seems to work better.
    Using Code::Blocks and Windows XP

    In every hero, there COULD be a villain!

  6. #6
    The superhaterodyne twomers's Avatar
    Join Date
    Dec 2005
    Location
    Ireland
    Posts
    2,273
    You could always template the structure so it will work with string arrays of different sizes. Though, of course, the template size will need to be known at compile time and the functions will have to be templated too.
    Code:
    template<int arrSize> 
    struct DATA
    {
        char    s1[arrSize];
        char    s2[arrSize];
        int     i1;
        int     i2;
        char    s3[arrSize];
        double  d1;
        double  d2;
        char    s4[arrSize];
    }; 
    
    ... 
    
    int main() {
      DATA<30> x, y;
    
      // etc...
    
      return 0;
    }

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Merge Binary Files
    By chinook86 in forum C Programming
    Replies: 7
    Last Post: 01-21-2008, 02:19 PM
  2. Reading Binary files
    By earth_angel in forum C++ Programming
    Replies: 10
    Last Post: 07-12-2005, 06:48 AM
  3. Binary Files
    By Axpen in forum C Programming
    Replies: 14
    Last Post: 08-12-2004, 08:41 PM
  4. How to store n write binary file?
    By megablue in forum C Programming
    Replies: 4
    Last Post: 10-23-2003, 03:53 AM
  5. Serial Communications in C
    By ExDigit in forum Windows Programming
    Replies: 7
    Last Post: 01-09-2002, 10:52 AM