将字节转换为位并将二进制数据写入文件

时间:2014-04-22 02:31:28

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

假设我有一个字符数组,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);
}

这是我在霍夫曼树的帮助下构建代码树的方法。并且

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

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

4 个答案:

答案 0 :(得分:1)

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

该函数提供无符号long值,因为您知道您的值在0-255范围内,您可以将其存储在unsigned char中:

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

将其写入磁盘,您可以使用ofstream来编写

  

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

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

编辑:其他详细信息

假设我们有一个长度的缓冲区,你在那里存储你的字符串'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); 

答案 1 :(得分:1)

将表示位表示的输入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位的值。

答案 2 :(得分:0)

一种方式:

/** 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);
   }

答案 3 :(得分:0)

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

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

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