c语言文件读写 huffman编码

来源:互联网 发布:纯种汉族人的特征 知乎 编辑:程序博客网 时间:2024/06/08 11:59

1.记一个大坑,在做huffman压缩时调了一个上午,如下所示,当使用w模式写入’\n’时,会被自动转化为’\r’和’\n’,而用wb则不会,a和ab同理。

    FILE *fp;    fopen_s(&fp, "file.dat", "w");//与wb的区别,a和ab同理    unsigned char ch = 0x0a;    fputc(ch, fp);    fclose(fp);    fopen_s(&fp, "file.dat", "rb");    unsigned char ch1, ch2, ch3;    ch1 = fgetc(fp);    ch2 = fgetc(fp);    ch3 = fgetc(fp);    fclose(fp);

代码运行情况

2.如何将长度不一的二进制串按一个字节一个字节的方式写入文件,注释中的想法每轮for循环,要么执行从code中取最左边一位的操作(同时i++),要么将一个完整的字节写入文件(i不增加),这样,如果同好code的最右边一位是待写入字节的第八位,则for循环中断(因为i等于code.size),则不会执行里面的if语句,导致无法正确写入。
正确的做法是在每次从code中取最左边一位之后,立即检测是否已经可以将一个完整的字节写入文件中。

while (!feof(fp1))        {            code = charEntities[rawChar].code;//长度不确定的0、1串            for (int i = 0; i < code.size();)            {                //printf("i=%d,code.size=%d\n", i, code.size());                //cout << "i=" << i << " code.size=" << code.size() << "\n";                /*if (size == 8)//如果刚好i为code.size,则这个语句无法执行                {                    fputc(bcode, fp2);                    bcode = 0;                    size = 0;                }                else                {                    bcode <<= 1;                    bcode |= code[i] - '0';                    ++size;                    ++i;                }*/                bcode <<= 1;                bcode |= code[i] - '0';                cnt++;                ++size;                ++i;                if (size == 8)                {                    fputc(bcode, fp2);//如果用a而不是ab模式,00001010写入之后会变成0x0d0a                    fflush(fp2);                    bcode = 0;                    size = 0;                }            }            rawChar = fgetc(fp1);        }

3.上面过程的逆过程,将文件的内容一个字节一个字节的读出来,用一个i指示当前处理到的位置,默认i不断增加,如果文件还能继续读取,则当i走到最后时(这里是7),重新从文件中读出一个新的字节,并将i重置为0(由于for循环会自动加一,这里设为-1),这样便能够把文件中的内容全部分块取出,并按需要对每个位进行处理。

for (int i = 0; i < 8; i++)        {            flag = character >> 7;            character <<= 1;            cnt++;            if (flag)            {                node = node->right;            }            else            {                node = node->left;            }            if (node->left == NULL)            {                fputc(node->character, fp2);                totalCharacterCnt--;                if (totalCharacterCnt == 0)                {                    break;                }                node = root;            }            //当处理完最后一个字符时,从文件中重新读入1个字节            if (i == 7)            {                character = fgetc(fp1);                if (feof(fp1))                {                    break;                }                i = -1;            }        }

4.下方,node->word是string类型,直接使用fwrite会出现乱码,得转成node->word.c_str(),这是将字符串写入文件的方法,对int等普通变量,如int a,只需要在写成fwrite(&a,sizeof(a),1,fp)

    size = node->word.size();    //printf(">--%s--<已写入\n", node->word.c_str());    fwrite(node->word.c_str(), size, 1, fp2);

5.在将一个单词写入文件中后,要记得把word串清空,否则由于word不断增大,在调用dictionary[word].freq = freq后,会使内存急剧增大,从而导致程序崩溃。

//依次读出各个单词的内容及其频率        while (wordCnt > 0)        {            ch = fgetc(fp1);            while (ch != specialChar)            {                word += ch;                ch = fgetc(fp1);            }            fread(&freq, sizeof(int), 1, fp1);            dictionary[word].freq = freq;            word = "";//--?????--            wordCnt--;        }

6.打开文件后一定要记得关闭,我在一个函数fopen_s打开文件后,忘记关掉,在另一个文件打调用fopen_s就无法打开文件,导致后面调用fseek和ftell 出错