简体   繁体   中英

Write file in binary format

I am trying to write the file in binary format. I have the following code with me, but it save the file in text format.

#include <iostream>
#include <fstream>

using namespace std;

int main(){
    std::string ref = "Ecoli. 123";
    unsigned int size = 124;

    std::ofstream supp_info_output("binary_file",  std::ios::out | std::ios::binary); // saving file
    supp_info_output << ref << std::endl;
    supp_info_output << size << std::endl;
    supp_info_output.close();

    std::ifstream supp_info_input("binary_file", std::ios::in | std::ios::binary); // loading file
    std::string supp_info_line;
    while( std::getline( supp_info_input, supp_info_line ).good() ){
        std::cout << supp_info_line << std::endl;
    }
    supp_info_input.close();
}

In the code I am writing some data and then reading the data again. There is no problem in reading and writing,but I need the file in binary format.

Use ofstream::write to write binary data and ifstream::read to read them. Note, that you should save the length of strings because you should know how many bytes to read further.

std::string ref = "Ecoli. 123";
unsigned int size = 124;

std::ofstream supp_info_output("binary_file",  std::ios::out | std::ios::binary); // saving file
unsigned int stringLength = ref.length();
supp_info_output.write( (char*)( &stringLength ), sizeof( stringLength ) );
supp_info_output.write( ref.c_str(), ref.length() );
supp_info_output.write( (char*)( &size ), sizeof( size ) );
supp_info_output.close();

And here is how to read:

std::string ref;
unsigned int size;

std::ifstream supp_info_input("binary_file", std::ios::in | std::ios::binary); // loading file
unsigned int stringLength;
supp_info_input.read( (char*)( &stringLength ), sizeof( stringLength ) );
ref.resize( stringLength );
supp_info_input.read( (char*)ref.c_str(), stringLength );
supp_info_input.read( (char*)( &size ), sizeof( size ) );
supp_info_input.close();

As commented on answer from AwaitedOne I dislike writing a lot of code for every single output statement. Instead I prefer having a overload for shift operator to make user code a bit easier and less error prone.

As a startpoint the following example is given. There are not all possible overloads presented and also the BinaryFile class is less then "ready for production". It is only given as a compileable startpoint to start own investigations.

Keep in mind: binary file is not portable, binary representation can change from version to version of compiler/libc/other. It is also dependend of OS and endianess of system and also of the architecture ( 32 vs 64 bit ) and many others.

So binary data should not be used in general to make data persistent for "later" use unless you write handler methods, which have a defined in/out format. My example write simple the memory of the storage of the data which is very stupied and results in all the problems are mentioned. Feel free to start an own "perfect" implementation for an exchangeable binary format.

But instead of reinvent the whell, someone should use ready to use implementations given already everywhere. Search for "serializer" and you will find a good set of libs like boost serialize and many others.

#include <fstream>
#include <cstring>

class BinaryOut: public std::ofstream
{ 
    public:
        BinaryOut( const char* fname ):
           std::ofstream( fname, std::ios::binary )
    {}

};

// use a generic func to use for everything which not handled in special way
template < typename DataType >
BinaryOut& operator << ( BinaryOut& out, const DataType& data )
{
    out.write( (char*)&data, sizeof( DataType ));
    return out;
}

// if pointer type, write not pointer but values which pointer points to:
template < typename DataType >
BinaryOut& operator << ( BinaryOut& out, const DataType*& data )
{
    out.write( (char*)data, sizeof( DataType ));
    return out;
}

// special case for char ptr ( old style c string ) which ends with '\0'
// use old style c here ( no std::string is involved )
BinaryOut& operator << ( BinaryOut& out, const char* ptr )
{
    out.write( ptr, strlen( ptr ));
    return out; 
}

// may be some more overloads for << if needed...

int main()
{
    BinaryOut out("example.bin");

    int i=123;
    double d=9.876;
    double* ptrd=&d;

    const char* dummy = "Ptr to Text";

    out << i << d  << ptrd << "Hallo, this is a test" << dummy;
}

It's slightly more difficult than it looks to write data in binary. I suggest using the C FILE * interface, because many C++ programmers overload << and >> to insert and extract higher-level objects, in text mode. You lose that when you go to binary.

To insert an integer, you need to know if it is 16 bit or 32 bit, big-endian or little-endian. You then use shifts and masks and calls to fputc() to write the bytes directly. To insert an asciiz string, similarly call fputc and ensure that you write the nul.

@Klaus is right, if you pass int to << in a binary file, it just writes text to file. If you want to write int binary to file with <<, you should pass the bytes stream to <<. For example, in your code, you need to write the 4 bytes of the int each time with <<, then binary int will be written to your file. You can check below code:

#include "stdafx.h"

#include <iostream>
#include <fstream>

using namespace std;

union data {
    int i;
    char bytes[4];
};

int main(){
    data src;
    src.i = 0xabcddcba;

    std::ofstream supp_info_output("binary_file", ios::out | ios::binary); // saving file
    supp_info_output << src.bytes[0];
    supp_info_output << src.bytes[1];
    supp_info_output << src.bytes[2];
    supp_info_output << src.bytes[3];
    supp_info_output.close();

    data dst;
    dst.i = 0;
    std::ifstream supp_info_input("binary_file", ios::in | ios::binary); // loading file
    supp_info_input >> dst.bytes[0];
    supp_info_input >> dst.bytes[1];
    supp_info_input >> dst.bytes[2];
    supp_info_input >> dst.bytes[3];
    supp_info_input.close();

    std::cout << ((src.i == dst.i)?"Pass check.":"Failed check.") << std::endl;

    getchar();
}

I think the behavior of << in binary file mode is expected, because in binary file mode everything should be treated as bytes stream regardless of its type such as int, double, short int, ... etc.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM