如何将矢量<bool>或bitset存储到文件中,但是按位?</bool>

时间:2011-01-12 08:00:06

标签: c++ file stl vector bitset

How to write bitset data to a file?

第一个答案没有正确回答问题,因为它需要的空间比它应该多8倍。

你会怎么做?我真的需要它来保存很多真/假值。

6 个答案:

答案 0 :(得分:6)

最简单的方法:连续获取8个布尔值,将它们表示为单个字节,将该字节写入文件。那会节省很多空间。

在文件的开头,您可以写入要写入文件的布尔值的数量;从读取文件中的字节并将它们转换回布尔值时,该数字将有所帮助!

答案 1 :(得分:2)

这是一个尝试两个函数,它们将使用最少的字节数,而不压缩位集。

template<int I>
void bitset_dump(const std::bitset<I> &in, std::ostream &out)
{
    // export a bitset consisting of I bits to an output stream.
    // Eight bits are stored to a single stream byte.
    unsigned int i = 0;  // the current bit index
    unsigned char c = 0; // the current byte
    short bits = 0;      // to process next byte
    while(i < in.size())
    {
        c = c << 1;       //
        if(in.at(i)) ++c; // adding 1 if bit is true
        ++bits;
        if(bits == 8)
        {
            out.put((char)c);
            c = 0;
            bits = 0;
        }
        ++i;
    }
    // dump remaining
    if(bits != 0) {
        // pad the byte so that first bits are in the most significant positions.
        while(bits != 8)
        {
            c = c << 1;
            ++bits;
        }
        out.put((char)c);
    }
    return;
}

template<int I>
void bitset_restore(std::istream &in, std::bitset<I> &out)
{
    // read bytes from the input stream to a bitset of size I.
    /* for debug */ //for(int n = 0; n < I; ++n) out.at(n) = false;
    unsigned int i = 0;          // current bit index
    unsigned char mask = 0x80;   // current byte mask
    unsigned char c = 0;         // current byte in stream
    while(in.good() && (i < I))
    {
        if((i%8) == 0)           // retrieve next character
        { c = in.get();
          mask = 0x80;
        }
        else mask = mask >> 1;   // shift mask
        out.at(i) = (c & mask);
        ++i;
    }
}

请注意,可能使用bitset使用的内存部分的reinterpret_cast作为字符数组也可以工作,但它可能不能跨系统移植,因为你不知道bitset的表示是什么(endianness) ?)

答案 2 :(得分:2)

如果你想要最好支持转换为二进制的bitset类,并且你的bitset大于unsigned long的大小,那么最好使用的选项是boost::dynamic_bitset。 (如果您担心节省空间,我认为它超过32位甚至64位。)

从dynamic_bitset,您可以使用to_block_range将位写入基础整数类型。您可以使用from_block_range或BlockInputIterator中的构造函数或通过调用append()来从块中构造dynamic_bitset。

现在你有了原生格式(Block)的字节,你仍然有把它写入流并将其读回来的问题。

您需要先存储一些“标题”信息:您拥有的块数以及可能的字节序。或者您可以使用宏转换为标准字节序(例如ntohl,但理想情况下,您将使用非最常用平台的宏,因此如果这是小端,您可能希望以这种方式存储并仅转换为大端系统)。

(注意:我假设boost :: dynamic_bitset标准地以相同的方式转换整数类型而不管底层的字节顺序。他们的文档没有说明。)

要使用os.write( &data[0], sizeof(Block) * nBlocks )将二进制数写入流,并且读取使用的是。read( &data[0], sizeof(Block) * nBlocks ),其中数据假定为vector<Block>,在阅读之前,您必须执行data.resize(nBlocks)(不是reserve())。 (您也可以使用istream_iteratoristreambuf_iterator做一些奇怪的事情,但resize()可能更好。)

答案 3 :(得分:1)

一种方式可能是:

std::vector<bool> data = /* obtain bits somehow */

// Reserve an appropriate number of byte-sized buckets.
std::vector<char> bytes((int)std::ceil((float)data.size() / CHAR_BITS)); 

for(int byteIndex = 0; byteIndex < bytes.size(); ++byteIndex) {
   for(int bitIndex = 0; bitIndex < CHAR_BITS; ++bitIndex) {
       int bit = data[byteIndex * CHAR_BITS + bitIndex];

       bytes[byteIndex] |= bit << bitIndex;
   }
}

请注意,这假设您不关心位布局最终在内存中是什么,因为它不会对任何内容进行任何调整。但是,只要您同时序列化实际存储的位数(以覆盖您的位数不是CHAR_BITS的倍数的情况),您可以反序列化完全相同的位集或向量,就像您最初这样

(我对这个桶大小的计算不满意,但是凌晨1点,我无法想到更优雅的东西)。

答案 4 :(得分:0)

#include "stdio"
#include "bitset"
...
FILE* pFile;
pFile = fopen("output.dat", "wb");
...
const unsigned int size = 1024;
bitset<size> bitbuffer;
...
fwrite (&bitbuffer, 1, size/8, pFile);
fclose(pFile);

答案 5 :(得分:-2)

两个选项:

为更大的磁盘花费额外的磅(或便士,更可能)。

编写一个例程,一次从bitset中提取8位,将它们组成字节,然后将它们写入输出流。