如何在文件中打印位而不是字节
How can I print a bit instead of byte in a file?
我正在使用霍夫曼算法来开发文件压缩器,现在我面临着一个问题:
通过使用算法到单词:堆栈溢出,我得到以下结果:
a,c,e,f,k,l,r,s,t,v,w = 1 time repeated
o = 2 times repeated
a,c,e,f,k,l,r,s,t,v,w = 7.69231%
and
o = 15.3846%
所以我开始插入到二叉树中,这将得到我的结果:
o=00
a=010
e=0110
c=0111
t=1000
s=1001
w=1010
v=1011
k=1100
f=1101
r=1110
l=1111
这意味着树中字符的路径,认为 0 是左边,1 是右边。
那么"堆栈溢出"这个词将是:100110000100111010011111000010110110111011011111001010
好吧,我想将整个值放入二进制文件中以位为单位,这将导致 47 位,恰好是 6 字节,但我只能使其成为 47 字节,因为放入带有 fwrite 或 fprintf 的文件中的最小值是 1byte,通过使用 sizeof(something)。
比我的问题是:我怎么能只在我的文件中打印一个位?
只需将"标头"写入文件:位数,然后将位"打包"为字节,填充最后一个。下面是一个示例。
#include <stdio.h>
FILE* f;
/* how many bits in current byte */
int bit_counter;
/* current byte */
unsigned char cur_byte;
/* write 1 or 0 bit */
void write_bit(unsigned char bit)
{
if(++bit_counter == 8)
{
fwrite(&cur_byte,1,1,f);
bit_counter = 0;
cur_byte = 0;
}
cur_byte <<= 1;
cur_byte |= bit;
}
int main()
{
f = fopen("test.bits", "w");
cur_byte = 0;
bit_counter = 0;
/* write the number of bits here to decode the bitstream later (47 in your case) */
/* int num = 47; */
/* fwrite(num, 1, 4, f); */
write_bit(1);
write_bit(0);
write_bit(0);
/* etc... - do this in a loop for each encoded character */
/* 100110000100111010011111000010110110111011011111001010 */
if(bit_counter > 0)
{
// pad the last byte with zeroes
cur_byte <<= 8 - bit_counter;
fwrite(&cur_byte, 1, 1, f);
}
fclose(f);
return 0;
}
当然,要完成完整的霍夫曼编码器,您必须在开始时编写位代码。
这是一个编码问题。问题是文件只能包含字节 - 所以 1 和 0 在文件中只能是"1"和"0" - 1 和 0 的字符,它们是字节。
您需要做的是将位打包成字节,创建一个包含一组字节中的位的文件。您将无法在文本编辑器中打开文件 - 它不知道您要将每个位显示为 1 或 0 个字符,它将显示每个打包的字节。不过,您可以使用了解如何使用二进制文件的编辑器打开它。例如,vim 可以做到这一点。
至于额外的尾随字节或文件结束标记,您将不得不创建某种编码约定。例如,你可以用额外的零打包和填充,就像你在评论中提到的那样,但按照惯例,前 N 个字节是元数据 - 例如数据长度,文件中有多少位是有趣的。这种事情很常见。
您需要自己管理它,通过缓冲要写入的位,并且仅在具有完整字节时才实际写入数据。像...
void writeBit(bool b)
{
static char buffer=0;
static int bitcount=0;
buffer = (buffer << 1) | (b ? 1:0);
if (++bitcount == 8)
{
fputc(buffer); // write out the byte
bitcount = 0;
buffer = 0;
}
}
以上不是可重入的(并且可能效率很低) - 你需要确保你以某种方式刷新任何半写的字节在最后,(写额外的 7 个零位,也许),但你应该得到一般的想法。
- 如何使用Crypto++并为RSA返回可打印的字节/字符数组
- 读取文件中所有可能的十六进制 16 字节序列并打印每个序列
- 将字节打印为长字节
- 我该如何循环遍历我的数组(缓冲区——包含一个文本文件),并将其打印成30字节的块
- 在 Visual Studio 调试器中,如何从内存中打印字节范围?
- C/C++ 以十六进制打印字节,得到奇怪的十六进制值
- 在C中垂直打印字节数组
- 如何将二进制字节转换为可打印的数值
- 将 MFRC522 UID 十六进制字节转换为可打印的小数
- 如何在文件中打印位而不是字节
- 手动打印 N 字节整数
- 如何在 4 字节整数中打印出每个字节的内容
- 如何将字节打印为十六进制
- 一次打印 2 个字节的十六进制数字
- 在Qt中打印8字节整数时出错
- 将整数打印为以小端序排列的4个字节的集合
- 以十六进制或十进制形式将std::字符串作为字节序列打印到stdout
- 打印字节的正确类型转换
- 打印字节序列
- Regex不可打印字节