2

I want to store the example below onto harddisk as a simple binary file. But around the net I havn't found any simple and clean example how to do it, so I'm questioning:

How to modify code below to store the struct as binary in a binary file?

#include <vector>
#include <string>
#include <bitset>
#include <boost/serialization/string.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/bitset.hpp>

template<size_t N>
struct Example
{
  std::string id;
  std::vector<std::bitset<N>> bits;
};

template<size_t N>
Example<N> make_example()
{
  Example<N> example;

  example.id = "some id";

  example.bits.resize(100);
}

namespace boost
{
  namespace serialization
  {
    template<typename Archive, size_t N>
    void serialize ( Archive & a
                   , Example<N> & e
                   , const unsigned int version )
    {
        a & e.id;
        a & e.bits;
    }
  }
}

int main()
{
  auto example = make_example<256>();

  std::ofstream ofs("filename", std::ios::binary);

  boost::archive::binary_oarchive oa(ofs);

  oa << example; // shouldn't use << as oa writes a text archive
}
user1587451
  • 978
  • 3
  • 15
  • 30

1 Answers1

3

I believe the issues are:

  1. Need to return the example in make_example(). You are probably getting a compiler warning here that you ignored.
  2. Need to #include <boost/archive/binary_oarchive.hpp>. Otherwise, it should not even compile.

Also, your comment // shouldn't use << as oa writes a text archive is not quite correct because << is now overloaded for boost::archive::binary_oarchive so that it is streaming binary.

Therefore, the modified code should look like:

#include <vector>
#include <string>
#include <bitset>
#include <fstream>
#include <boost/serialization/string.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/bitset.hpp>
// ADD THIS!!!
#include <boost/archive/binary_oarchive.hpp>

template<size_t N>
struct Example
{
  std::string id;
  std::vector<std::bitset<N>> bits;
};

template<size_t N>
Example<N> make_example()
{
  Example<N> example;

  example.id = "some id";

  example.bits.resize(100);
  // ADD THIS!!!
  return(example);
}

namespace boost
{
  namespace serialization
  {
    template<typename Archive, size_t N>
    void serialize ( Archive & a
                   , Example<N> & e
                   , const unsigned int version )
    {
        a & e.id;
        a & e.bits;
    }
  }
}

int main()
{
  auto example = make_example<256>();

  std::ofstream ofs("filename", std::ios::binary);

  boost::archive::binary_oarchive oa(ofs);

  oa << example;

  return(0);
}

A related example on SO is here.


Update To make the binary serialization of std::bitset more compact

Look at the SO answer by @6502 here. You will then need to:

  1. Split your serialize function into separate load and save functions. See this (under Tutorial::Splitting serialize into save/load) for an example.
  2. In save, iterate over e.bits and use @6502's bitset_to_bytes function to convert EACH of the e.bits[i] to a std::vector<unsigned char>. You will then have a std::vector<std::vector<unsigned char>> (a local variable in the save function). Serialize that.
  3. Conversely, in load, unserialize to get a std::vector<std::vector<unsigned char>> (again, local variable in load). Then, iterate over that collection and use @6502's bitset_from_bytes<N> function to convert EACH std::vector<unsigned char> to e.bits[i].
  4. Remove the #include <boost/serialization/bitset.hpp>, you no longer need it.

This should bring the storage of each std::bitset<N> from N to (N+7)/8 bytes in the binary archive.

Hope this helps.

Community
  • 1
  • 1
aichao
  • 7,375
  • 3
  • 16
  • 18
  • Indeed, I had some copy/paste errors in my previous post. I edited right the way you proposed. When I run the program, the genereated file _filename_ shows text-content like this (~ 25600 characters as expected): `^@^D^H^D^H^A^@^@^@^@^@^@^@^@^G^@^@^@^@^@^@^@some id^@^@^@^@^@d^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^A^@^@^@^@^@^@0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000^@^A^@^@^@^@^@^@0` – user1587451 Jul 22 '16 at 09:50
  • So, this works but still it is not the expected output. The filesize is around 26K, but 256*100bit=3200byte=3,125K. The filesize is ~8 times bigger as expected. – user1587451 Jul 22 '16 at 09:54
  • 2
    @user1587451 indeed, but that is the binary archive. Change to text_oarchive and include the corresponding header to see the difference. The difference will be slight for your case because of the bitsets, but with the text archive there will be more text metadata. – aichao Jul 22 '16 at 10:00
  • 1
    Is there a way to shrink the size further? – user1587451 Jul 22 '16 at 10:20
  • 2
    @user1587451 please look at my updated answer. Try it out. I haven't, but am curious of the result. It should work. Good luck! – aichao Jul 22 '16 at 11:15