如何每次将“一位”写入文件流或文件结构?
是否可以写入队列然后刷新它?
是否可以使用C#或Java?
在尝试实现霍夫曼编码实例时需要这样做。我无法将位写入文件,因此将它们写入位集然后(当压缩完成时)每次写入8位(排除最后一位)。
答案 0 :(得分:13)
缓冲各个位直到你累积了整个字节似乎是一个好主意:
byte b;
int s;
void WriteBit(bool x)
{
b |= (x ? 1 : 0) << s;
s++;
if (s == 8)
{
WriteByte(b);
b = 0;
s = 0;
}
}
当要写入的位数不是8的倍数时,您只需要处理这种情况。
答案 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
作为模板参数,我将unsigned char
8位的块大小设置为。您可以通过指定更大的整数类型来使块大小更大。
boost::to_block_range
将块中的bitset转储给给定的输出迭代器。如果最后一个块中有空的剩余位,则它们将用零填充。
当我在十六进制编辑器中打开data.dat时,我看到:AA 05
。这是一个小端平台(x64)。
答案 2 :(得分:3)
您使用的是哪个文件系统?
很可能它以字节为单位存储文件的长度(是否任何不存在?),因此不可能有一个不是整数字节的物理文件。 / p>
因此,如果您将文件作为位流写入,则必须在完成时截断最后几位,或者在剩余位中写出最后一个字节,并将其写入垃圾。
这里有一些 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)
答案 3 :(得分:0)
你不能真的。我很确定问题不在于语言或文件系统,而在于硬件问题。处理器旨在使用字节。可能你最接近的就是一遍又一遍地写下你的最后一个字节,右边用零填充,随时改变它们,一次一个。
所以要写位'11011',您可以执行以下操作(python示例,但任何语言都应该有设施来执行此操作:
f.write(chr(0b10000000))
f.flush()
f.seek(-1)
f.write(chr(0b11000000))
f.flush()
f.seek(-1)
f.write(chr(0b11000000))
f.flush()
f.seek(-1)
f.write(chr(0b11010000))
f.flush()
f.seek(-1)
f.write(chr(0b11011000))
f.flush()
你不希望从中获得某种性能提升吗?
答案 4 :(得分:0)
我建议分配一个相当大的缓冲区(至少4096字节),并在它填满时将其刷新到磁盘。使用单字节缓冲区通常会导致性能下降。
答案 5 :(得分:0)
我为霍夫曼解码做了一次,最后将这些位写成字符,从而在内部处理所有内容,作为普通的旧C字符串。
这样你就不必担心尾随字节,它也是人类可读的。同样检查位是更容易的,因为它只是解决char数组(binbuf[123] == '1'
)而不是必须摆弄位。不是最优化的解决方案,但它整齐地解决了我的问题。
明显的缺点是这种表示使用了更多的内存。
答案 6 :(得分:0)
这里的问题是许多平台没有直接位访问权限。它们将位分组为最小包,通常是字节或字。而且,流设备的协议不利于各个比特的传输。
处理单个位的常用方法是将它们打包到最小的便携式和(可寻址)可访问单元中。未使用的位通常设置为零。这可以通过二进制算术运算(OR,AND,EXCLUSIVE-OR,NOT等)来完成。
使用现代处理器,比特混乱会降低机器和性能。内存便宜且具有大的寻址空间,比特打包的理由变得更加困难。通常,比特打包被保留用于面向硬件的操作(以及传输协议)。例如,如果处理器的字容量为16位,则处理器可能比一个字中的16位操作快16个字。
另外,请记住,从内存写入内容通常比来自内存的I / O更快。高效系统在传输数据之前缓冲存储器中的数据。您可能希望在设计中考虑这种技术。减少I / O操作将提高程序的性能。