答案 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_iterator
或istreambuf_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位,将它们组成字节,然后将它们写入输出流。