Skip to main content

Write and read binary files in C++

To write the EDDI compiler, I had to write and read binary files. Writing text files is really easy in C++, directly using the << operator on the stream, but writing binary is a little harder and, I must say, a lot less elegant.

First, to write to a binary file, we have to use the binary flag when we create the file :

std::ofstream stream("yourFile", std::ios::binary);

and then, we have to use the write method to write to the file. But this function is really basic and takes only a char and the size of the data we wan't to write, so we have to convert our data to char. A good way to do that is using the reinterpret_cast function and the sizeof operator. For example, to write an int, you can make that :

int test = 22;
outStream.write(reinterpret_cast<const char*>(&test), sizeof(int));

But your code is quickly polluted if you have of write operations to do.

We can simplify that, using a function template like this one :

template<typename T>
std::ostream& binary_write(std::ostream& stream, const T& value){
    return stream.write(reinterpret_cast<const char*>(&value), sizeof(T));
}

And you use it directly like that :

int test = 22;
binary_write(stream, test);

A little less verbose, isn't it ? You can also pass a class or struct instance directly tot his method. If you have complex objects, it's perhaps not the more proper way to do it, in that case, consider using some serialization API. If you have object with variable length, it will not work because the size cannot be computed with the sizeof operator. For example, this function doesn't work with a std::string because the sizeof operator doesn't represent the real size of the string. We can make another function to write string :

template<>
std::ostream& binary_write_string(std::ofstream& stream, const std::string& value){
    return stream->write(value.c_str(), value.length());
}

Then, to read a binary, you have also to open it with the binary tag :

std::ifstream inStream("yourFile", std::ios::binary);

And then, you have to use the read method to read your values :

int test;
inStream.read(reinterpret_cast<char*>(&test), sizeof(int));

Once again, we can create a function template to have a little better code :

template<typename T>
std::istream & binary_read(std::istream& stream, T& value){
    return stream.read(reinterpret_cast<char*>(&value), sizeof(T));
}

and you can use it the same way :

int test;
binary_read(stream, test);

Once again, this function will not work with the class or struct with variable size. Even with strings, there is no way to read them easily. If you want to read them, you'll have to write the size of the string directly in the file and then read the size before and you can read a char using the read method passing the size of the string and create a new string using the char.

With that, you are able to read and write to and from binary files.

Comments

Comments powered by Disqus