将'bits'写入C ++文件流

时间:2010-03-19 11:18:24

标签: java c# python c++ bit-manipulation

如何每次将“一位”写入文件流或文件结构?

是否可以写入队列然后刷新它?

是否可以使用C#或Java?

在尝试实现霍夫曼编码实例时需要这样做。我无法将位写入文件,因此将它们写入位集然后(当压缩完成时)每次写入8位(排除最后一位)。

7 个答案:

答案 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_bitsetstd::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操作将提高程序的性能。

相关问题