将位写入文件?

时间:2017-12-21 16:35:10

标签: c++ binary ofstream huffman-code

我正在尝试实现一个霍夫曼树。

我想做一个简单测试的简单.txt文件的内容:

aaaaabbbbccd

字符频率:a:5,b:4,c:2,d:1

代码表:(数据类型 1 s且 0 s:字符串

a:0
d:100
c:101
b:11         

我想写成二进制文件的结果:(22位)

0000011111111101101100          

如何将 逐位 将此结果的每个字符作为二进制文件写入“.dat”文件? (不是字符串)

3 个答案:

答案 0 :(得分:4)

答案:你不能。

您可以写入文件(或从中读取)的最小金额为charunsigned char。出于所有实际目的,char只有8位。

您将需要一个char缓冲区,以及它所拥有的位数的计数。当该数字达到8时,您需要将其写出,并将计数重置为0.您还需要一种方法来在最后刷新缓冲区。 (不是你不能将22位写入文件 - 你只能写16或24.你需要一些方法来标记最后哪些位未被使用。)

类似的东西:

struct BitBuffer {
    FILE* file; // Initialization skipped.
    unsigned char buffer = 0;
    unsigned count = 0;

    void outputBit(unsigned char bit) {
         buffer <<= 1;         // Make room for next bit.
         if (bit) buffer |= 1; // Set if necessary.
         count++;              // Remember we have added a bit.
         if (count == 8) {
             fwrite(&buffer, sizeof(buffer), 1, file); // Error handling elided.
             buffer = 0;
             count = 0;
         }
    }
};

答案 1 :(得分:0)

OP问道:

  

如何将此结果的每个字符逐位写为“.dat”文件的二进制文件? (不是字符串)

你不能,这就是为什么......

  

记忆模型

     

为C ++抽象机器定义计算机内存存储的语义。

     

C ++程序可用的内存是 bytes 的一个或多个连续序列。内存中的每个字节都有一个唯一的地址

     

<强>字节

     

byte 是最小的可寻址内存单位。它被定义为一个连续的位序列,大到足以保存任何UTF-8代码单元(256个不同的值)和{em}基本执行字符集的任何成员{/ 1}}的值 (需要(since C++14)的96个字符。与C类似,C ++支持大小为8位且更大的single-byte

     

类型bytescharunsigned char使用一个字节表示存储和值。一个字节中的位数可以signed charCHAR_BIT访问。

std::numeric_limits<unsigned char>::digits

的致意

您可以在此处找到此页面:cppreference:memory model

这来自2017-03-21:标准

  

©ISO / IEC N4659

     

4.4 C ++内存模型 [intro.memory] ​​

     
      
  1. C ++内存模型中的基本存储单元是字节。一个字节至少足以包含基本执行字符集(5.3)的任何成员和Unicode UTF-8编码形式的八位代码单元,并由一个连续的位序列组成, 4 < / sup>其数量是实现定义的。最低有效位称为低位;最重要的位称为高位。 C ++程序可用的内存由一个或多个连续字节序列组成。每个字节都有一个唯一的地址。
  2.   
  3. [注意:类型的表示形式在6.9中描述。 - 结束记录]
  4.   
  5. 内存位置是标量类型的对象,或者是具有非零宽度的相邻位域的最大序列。 [注意:该语言的各种功能,例如引用和虚函数,可能涉及程序无法访问但由实现管理的其他内存位置。 - 结束注释]两个或多个执行线程(4.7)可以访问单独的内存位置而不会产生干扰   彼此。
  6.   
  7. [注意:因此,位字段和相邻的非位字段位于不同的存储单元中,因此可以通过两个执行线程同时更新而不会产生干扰。这同样适用于两个位字段,如果一个在嵌套的结构声明中声明而另一个未声明,或者两者是由零长度位字段声明分隔,或者它们是由非位分隔 - 现场声明。如果它们之间的所有字段也是非零宽度的位字段,则同时更新同一结构中的两个位字段是不安全的。 - 结束记录]
  8.   
  9. [示例:声明为

    的结构
    cppreference.com
         

    包含四个独立的内存位置:字段a和位字段d和e.ee是每个单独的内存   位置,并且可以同时修改而不会相互干扰。位域b和c   一起构成第四个记忆位置。位字段b和c不能同时修改,但是   例如,b和a可以。 - 结束示例]   

    <小时/>    4)一个字节中的位数由标题struct { char a; int b:5, c:11, :0, d:8; struct {int ee:8;} e; } 中的宏 CHAR_BIT 报告。

  10.   

此版本标准可在此处找到: 第8页上的www.open-std.org部分<climits>&amp; 9。

对于标准字节,可以在程序中写入的最小可能存储器模块是8个连续位或更多位。即使使用位字段,§ 4.4要求仍然有效。您可以在1 byte内操纵,切换,设置各个位,但不能单独编写byte

可以做的是使用bits缓冲区写入位数。写入所需位后,您需要将剩余的未使用位标记为bytepadding

修改

[注意:] - 使用un-used buffer bitsbit fields时,您必须考虑的一件事是{{1}特定架构。

答案 2 :(得分:0)

答案:可以。

您好,根据我的经验,我找到了一种简单的方法。对于此任务,您需要定义自己和字符数组(例如,仅需要1个字节,它可以更大)。之后,您必须定义函数以从任何元素访问特定位。例如,如何编写表达式以从C ++中的char中获取第3位的值。

*/*position is [1,..,n], and bytes 
are in little endian and index from 0`enter code here`*/
int bit_at(int position, unsigned char byte)
{
  return (byte & (1 << (position - 1)));
}*

现在您可以像这样想象字节数组 [b1,...,bn]

现在我们在内存中实际拥有的是8 * n位内存 我们可以尝试像这样可视化它。 注意:数组归零! | 0000 0000 | 0000 0000 | ... | 0000 0000 |

现在,您或任何人想要了解如何操纵它以从此数组中获取特定位。当然会有某种转换,但这不是问题。 最后,对于您提供的编码,即: a:0 d:100 c:101 b:11

我们可以对消息“ abcd”进行编码, 并创建一个包含位的数组 消息,使用元素 数组作为位数组,例如:

| 0111 0110 | 0000 0000 |

您可以将此内容写入内存,最多可以有7位多余的空间。 这是一个简单的示例,但可以扩展到更多示例。 我希望这能回答您的问题。