【问题标题】:Converting a byte into bit and writing the binary data to file将字节转换为位并将二进制数据写入文件
【发布时间】:2014-06-06 05:22:24
【问题描述】:

假设我有一个字符数组 char a[8] 包含 10101010。如果我将此数据存储在 .txt 文件中,则此文件有 8 个字节大小。现在我在问如何将这些数据转换为二进制格式并将其保存为 8 位(而不是 8 字节)的文件,以便文件大小只有 1 字节。

另外,一旦我将这 8 个字节转换为单个字节,我应该将输出保存为哪种文件格式? .txt 或 .dat 或 .bin?

我正在研究文本文件的霍夫曼编码。我已经将文本格式转换为二进制,即 0 和 1,但是当我将此输出数据存储在文件中时,每个数字(1 或 0)占用一个字节而不是一个位。我想要一个解决方案,每个数字只需要一点。

char buf[100];
void build_code(node n, char *s, int len)
{
static char *out = buf;
if (n->c) {
    s[len] = 0;
    strcpy(out, s);
    code[n->c] = out;
    out += len + 1;
    return;
}

s[len] = '0'; build_code(n->left,  s, len + 1);
s[len] = '1'; build_code(n->right, s, len + 1);
}

这就是我在 Huffman 树的帮助下构建代码树的方式。还有

void encode(const char *s, char *out)
{
while (*s) 
   {
    strcpy(out, code[*s]);
    out += strlen(code[*s++]);
    }
}

这就是我编码以获得最终输出的方式。

【问题讨论】:

  • 字符是 0 和 1,还是 '0' 和 '1'?一个关于如何构建数据的简短示例会有所帮助。
  • @Edward 我正在研究文本文件的霍夫曼编码。我已经将文本格式转换为二进制,即 0 和 1,但是当我将此输出数据存储在文件中时,每个数字(1 或 0)占用一个字节而不是一个位。我想要一个解决方案,使每个数字只需要一点点。要我分享完整的代码吗?
  • 一个简短的独立示例会很有用。从你的描述很难看出你实际拥有什么。如果您已将数据转换为二进制,则每位不会有一个数字。
  • @RetiredNinja 这是'0'和'1'
  • how to ask 的概述可能会有所帮助。

标签: c++ file compression byte huffman-code


【解决方案1】:

不完全确定你最终如何得到一个表示值的二进制表示的字符串, 但是您可以使用std::strtoul 等标准函数从字符串(任何基数)中获取整数值。

该函数提供一个无符号长整数值,因为您知道您的值在 0-255 范围内,您可以将其存储在无符号字符中:

unsigned char v=(unsigned char)(std::strtoul(binary_string_value.c_str(),0,2) & 0xff);

写入磁盘,可以使用ofstream写入

我应该以哪种文件格式保存输出? .txt 或 .dat 或 .bin?

请记住,扩展名(.txt、.dat 或 .bin)并不真正要求格式(即内容的结构)。扩展是commonly的约定,用于表明您正在使用一些众所周知的格式(并且在某些操作系统/环境中,它会驱动哪个程序最适合的配置处理该文件)。由于这是您的文件,因此由您来定义实际格式......并使用您最喜欢的任何扩展名(甚至没有扩展名)命名文件(或者换句话说,最能代表您的内容的任何扩展名)为只要它对您和那些将要使用您的文件的人有意义。

编辑:附加细节

假设我们有一个一定长度的缓冲区,您将在其中存储“0”和“1”字符串

int codeSize; // size of the code buffer
char *code;   // code array/pointer
std::ofstream file; // File stream where we're writing to.


unsigned char *byteArray=new unsigned char[codeSize/8+(codeSize%8+=0)?1:0]
int bytes=0;
for(int i=8;i<codeSize;i+=8) {
    std::string binstring(code[i-8],8); // create a temp string from the slice of the code
    byteArray[bytes++]=(unsigned char)(std::strtoul(binstring.c_str(),0,2) & 0xff);
}

if(i>codeSize) {
    // At this point, if there's a number of bits not multiple of 8, 
    // there are some bits that have not
    // been writter. Not sure how you would like to handle it. 
    // One option is to assume that bits with 0 up to 
    // the next multiple of 8... but  it all depends on what you're representing.
}

file.write(byteArray,bytes); 

【讨论】:

  • 我刚刚用我的代码编辑了问题内容。请看看并建议我该怎么做。谢谢。
【解决方案2】:

函数将输入的 8 个表示位表示的字符转换为一个字节。

char BitsToByte( const char in[8] )
{
    char ret = 0;
    for( int i=0, pow=128;
         i<8;
         ++i, pow/=2;
        )
        if( in[i] == '1' ) ret += pow;
    return ret;
}

我们迭代传递给函数的数组(出于明显的原因,大小为 8),并根据它的内容增加我们的返回值(数组中的第一个元素代表最旧的位)。 pow 设置为 128,因为 2^(n-1) 是第 n 位的值。

【讨论】:

    【解决方案3】:

    您可以很容易地将它们转换为一个字节,如下所示:

    byte x = (s[3] - '0') + ((s[2] - '0') << 1) + ((s[1] - '0') << 2) + ((s[0] - '0') << 3);
    

    在我的示例中,我只移动了一个半字节或 4 位。您可以扩展示例以移动整个字节。此解决方案将比循环更快。

    【讨论】:

      【解决方案4】:

      一种方式:

      /** Converts 8 bytes to 8 bits **/
      unsigned char BinStrToNum(const char a[8])
         {
         return(  ('1' == a[0]) ? 128 : 0
                + ('1' == a[1]) ? 64  : 0
                + ('1' == a[2]) ? 32  : 0
                + ('1' == a[3]) ? 16  : 0
                + ('1' == a[4]) ? 8   : 0
                + ('1' == a[5]) ? 4   : 0
                + ('1' == a[6]) ? 2   : 0
                + ('1' == a[7]) ? 1   : 0);
                );
         };
      

      以您提到的任何格式保存它;或发明你自己的!

      int main()
         {
         rCode=0;
         char *a = "10101010";
         unsigned char byte;
         FILE *fp=NULL;
      
         fp=fopen("data.xyz", "wb");
         if(NULL==fp)
            {
            rCode=errno;
            fprintf(stderr, "fopen() failed. errno:%d\n", errno);
            goto CLEANUP;
            }
      
         byte=BinStrToNum(a);
         fwrite(&byte, 1, 1, fp);
      
      CLEANUP:
      
         if(fp)
            fclose(fp);
      
         return(rCode);
         }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-12-05
        • 2015-10-27
        • 2014-06-09
        • 1970-01-01
        • 2017-06-25
        • 2010-12-08
        • 2017-11-22
        • 2011-01-25
        相关资源
        最近更新 更多