将“位”写入C++文件流
我该如何每次将“一位”数据写入文件流或文件结构呢?
可以先写入一个队列,然后再清空它吗?
用C#或Java可以做到吗?
这个问题是在尝试实现霍夫曼编码的时候遇到的。我不能直接把位写入文件,所以我先把它们写入一个位集合,然后在压缩完成后,每次写入其中的8位(最后一位除外)。
7 个回答
3
你在用什么文件系统呢?
大多数情况下,它会以字节为单位存储文件的长度(有没有不这样做的呢?),所以不可能有一个文件的大小不是整数个字节。
所以如果你是以比特流的方式写入文件,完成后你要么得把最后几位截断,要么就得把最后一个字节写出来,剩下的位就变成了无用的垃圾。
这里有一些Python代码可以帮助你入门
class BitFile(file):
def __init__(self, filename, mode):
super(BitFile, self).__init__(filename, mode)
self.bitCount=0
self.byte = 0
def write(self, bit):
self.bitCount+=1
self.byte = self.byte*2+bit
if self.bitCount%8==0:
super(BitFile, self).write(chr(self.byte))
self.byte=0
def close(self):
if self.bitCount%8!=0:
super(BitFile, self).write(chr(self.byte))
super(BitFile, self).close()
with BitFile("bitfile.bin","w") as bf:
bf.write(1)
bf.write(1)
bf.write(1)
bf.write(0)
bf.write(0)
bf.write(0)
bf.write(0)
bf.write(0)
bf.write(1)
8
你可以使用boost::dynamic_bitset
和std::ostream_iterator
来简单地实现你想要的效果:
#include <fstream>
#include <iterator>
#include <boost/dynamic_bitset.hpp>
typedef boost::dynamic_bitset<unsigned char> Bitset;
// To help populate the bitset with literals */
Bitset& operator<<(Bitset& lhs, bool val) {lhs.push_back(val); return lhs;}
int main()
{
Bitset bitset;
bitset<<0<<1<<0<<1<<0<<1<<0<<1
<<1<<0<<1<<0;
std::ofstream os("data.dat", std::ios::binary);
std::ostream_iterator<char> osit(os);
boost::to_block_range(bitset, osit);
return 0;
}
我把我的dynamic_bitset
的块大小设置为8位,方法是把unsigned char
作为模板参数。如果你想要更大的块大小,可以选择一个更大的整数类型。
boost::to_block_range
会把位集合以块的形式输出到指定的输出迭代器。如果最后一个块里有空余的位,它们会用零来填充。
当我在十六进制编辑器中打开data.dat时,我看到的是:AA 05
。这是在一个小端平台上(x64)。
13
把每一个比特(最小的信息单位)先存起来,等到凑够一个字节(8个比特)再一起处理,听起来是个不错的主意:
byte b;
int s;
void WriteBit(bool x)
{
b |= (x ? 1 : 0) << s;
s++;
if (s == 8)
{
WriteByte(b);
b = 0;
s = 0;
}
}
不过,你还得考虑一种情况,就是要写入的比特数量不是8的倍数的时候该怎么办。