【问题标题】:How does one store a vector<bool> or a bitset into a file, but bit-wise?如何将 vector<bool> 或 bitset 存储到文件中,但按位存储?
【发布时间】:2011-01-12 08:00:05
【问题描述】:

How to write bitset data to a file?

第一个答案没有正确回答问题,因为它占用的空间是应有的 8 倍。

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

【问题讨论】:

  • 实际上我并不关心它在我的问题中将每个位存储为一个字节......它只是措辞模棱两可。很好的后续问题。

标签: c++ file stl vector bitset


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

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

    您可以从 dynamic_bitset 使用 to_block_range 将位写入底层整数类型。您可以使用 from_block_range 或其构造函数从 BlockInputIterator 或通过调用 append() 从块中构造返回的 dynamic_bitset。

    现在您有了原生格式(块)的字节,您仍然有将其写入流并读回的问题。

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

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

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

    【讨论】:

    • 我用向量>做了一些代码,我稍后会测试它
    【解决方案3】:

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

    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;
        }
    }
    

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

    【讨论】:

      【解决方案4】:

      一种方法可能是:

      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 点,我无法想出更优雅的方法)。

      【讨论】:

        【解决方案5】:
        #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);
        

        【讨论】:

          【解决方案6】:

          两种选择:

          花额外的英镑(或便士,更有可能)购买更大的磁盘。

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

          【讨论】:

          • 好吧,我想尽可能多地存储,所以将容量增加 8 倍比买买买要好。
          猜你喜欢
          • 1970-01-01
          • 2020-04-02
          • 2021-07-24
          • 2016-01-12
          • 1970-01-01
          • 2015-09-30
          • 1970-01-01
          • 2011-05-08
          • 1970-01-01
          相关资源
          最近更新 更多