6

如何将位集数据写入文件?

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

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

4

6 回答 6

7

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

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

于 2011-01-12T08:03:07.200 回答
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;
    }
}

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

于 2011-01-12T09:17:00.553 回答
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( &data[0], sizeof(Block) * nBlocks )和读取使用是。read( &data[0], sizeof(Block) * nBlocks )假定数据在哪里,vector<Block>并且在读取之前您必须这样做data.resize(nBlocks)(不是reserve())。(你也可以用istream_iteratoror做一些奇怪的事情,istreambuf_iterator但 resize() 可能更好)。

于 2011-01-12T09:59:44.053 回答
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 点,我很难想出更优雅的东西)。

于 2011-01-12T08:46:09.243 回答
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);
于 2015-02-13T07:10:10.857 回答
-3

两种选择:

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

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

于 2011-01-12T08:03:08.357 回答