代码之家  ›  专栏  ›  技术社区  ›  sorush-r

将“位”写入C++文件流

  •  11
  • sorush-r  · 技术社区  · 14 年前

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

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

    用C或Java是可能的吗?

    在尝试实现哈夫曼编码的实例时,需要这样做。我不能将位写入文件,所以将它们写入一个位集,然后(当压缩完成时)每次写入其中的8位部分(不包括最后一个)。

    7 回复  |  直到 6 年前
        1
  •  13
  •   dtb    14 年前

    缓冲单个位直到您积累了一个完整的字节似乎是一个好主意:

    byte b;
    int s;
    
    void WriteBit(bool x)
    {
        b |= (x ? 1 : 0) << s;
        s++;
    
        if (s == 8)
        {
            WriteByte(b);
            b = 0;
            s = 0;
        }
    }
    

    当要写入的位数不是8的倍数时,您只需要处理这种情况。

        2
  •  8
  •   Emile Cormier    11 年前

    你可以用 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 将块中的位集转储到给定的输出迭代器。如果最后一个块中有空的余数位,它们将用零填充。

    当我在十六进制编辑器中打开dat a.dat时,我看到: AA 05 . 这是一个小endian平台(x64)。

        3
  •  3
  •   John La Rooy    14 年前

    您使用的是哪个文件系统?

    很可能它以字节为单位存储文件的长度(是否存在 任何 不是吗?)因此,不可能有一个不是整数字节的物理文件。

    因此,如果您将文件作为一个位流写入,那么您要么在完成后截断最后几个位,要么用剩余位中的垃圾值写出最后一个字节。

    这是一些 蟒蛇 启动代码

    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)
    
        4
  •  0
  •   Tronic    14 年前

    我建议分配一个相当大的缓冲区(至少4096字节),并在磁盘满时将其刷新到磁盘上。使用单字节缓冲区通常会导致性能不佳。

        5
  •  0
  •   jcdyer Anand S Kumar    14 年前

    你不能真的。我很确定问题不是语言或文件系统,而是硬件问题。处理器设计用于处理字节。也许你能做的最接近的就是一遍又一遍地写上最后一个字节,用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()
    

    你不希望从中获得某种性能提升,是吗?

        6
  •  0
  •   Thomas Matthews    14 年前

    这里的问题是许多平台没有直接的位访问。它们将比特分组成最小的包,通常是 字节 单词 . 此外,流设备的协议不促进单个位的传输。

    处理单个位的常用方法是将它们打包到最小的可移植(可寻址)可访问单元中。未使用的位通常设置为零。这可以通过二进制算术运算(或、和、异或、非等)来实现。

    使用现代处理器,位旋转会减慢机器和性能。内存便宜,寻址空间大,位封装的理由变得更加困难。通常,位打包是为面向硬件的操作(以及传输协议)而保留的。例如,如果处理器 单词 容量为16位,处理器处理16个字的速度可能比一个字处理16位字的速度快。

    另外,请记住,向内存写入和从内存写入通常比从流写入I/O要快。高效的系统在传输数据之前将数据缓冲在内存中。您可能想在设计中考虑这种技术。减少I/O操作将提高程序的性能。

        7
  •  0
  •   Martin Wickman    14 年前

    我曾经为哈夫曼解码做过一次,最后把比特写成了字符,这样就可以把内部的一切处理成一个普通的旧C字符串。

    这样就不必担心尾随字节,而且它也是人类可读的。此外,检查位更容易,因为它只是寻址char数组的问题。( binbuf[123] == '1' )而不必摆弄零碎的东西。不是最优化的解决方案,但它巧妙地解决了我的问题。

    明显的缺点是这种表示使用更多的内存。