无法将后续压缩数据写入C中的输出文件

时间:2019-05-01 19:27:47

标签: c file compression

我正在从输入文件读取数据,并使用C中的bzip库函数BZ2_bzCompress对其进行压缩。我可以成功压缩数据。但是我无法将所有压缩数据写入输出文件。只能写入第一条压缩线。我在这里想念什么吗?

int main()
{
    bz_stream bz;   
    FILE*   f_d;
    FILE* f_s;
    BZFILE* b;  
    int     bzerror = -10;  
    unsigned int nbytes_in;
    unsigned int nbytes_out;
    char buf[3000] = {0};
    int result = 0;
    char buf_read[500];
    char file_name[] = "/path/file_name";
    long int save_pos;

    f_d = fopen ( "myfile.bz2", "wb+" );    
    f_s = fopen(file_name, "r");

    if ((!f_d) && (!f_s)) {

        printf("Cannot open files");
        return(-1);
    }

    bz.opaque = NULL;
    bz.bzalloc = NULL;
    bz.bzfree = NULL;


    result = BZ2_bzCompressInit(&bz, 1, 2, 30); 


    while (fgets(buf_read, sizeof(buf_read), f_s) != NULL)
    {       
        bz.next_in = buf_read;
        bz.avail_in = sizeof(buf_read);
        bz.next_out = buf;
        bz.avail_out = sizeof(buf);

        printf("%s\n", buf_read);
        save_pos = ftell(f_d);
        fseek(f_d, save_pos, SEEK_SET);
        while ((result == BZ_RUN_OK) || (result == 0) || (result ==  BZ_FINISH_OK))
        {
            result = BZ2_bzCompress(&bz, (bz.avail_in) ? BZ_RUN : BZ_FINISH);                       

            printf("2 result:%d,in:%d,outhi:%d, outlo:%d \n",result, bz.total_in_lo32, bz.total_out_hi32, bz.total_out_lo32);
            fwrite(buf, 1, bz.total_out_lo32, f_d);         

        }
        if (result == BZ_STREAM_END)
        {
            result = BZ2_bzCompressEnd(&bz);                    
        }

        printf("3 result:%d, out:%d\n", result, bz.total_out_lo32);
        result = BZ2_bzCompressInit(&bz, 1, 2, 30); 
        memset(buf, 0, sizeof(buf));
    }   

    fclose(f_d);
    fclose(f_s);        
    return(0);
}

1 个答案:

答案 0 :(得分:1)

TL; DR:,但是有很多问题可以解释,您要解决的主要问题可能是您分别压缩文件的每一行,而不是整个文件


  1. 根据BZ2_bzCompressInit的文档,bz_stream参数应在调用之前分配并初始化。您的是(自动)分配的,但尚未(完全)初始化。更改为更清晰,更容易

        bz_stream bz = { 0 };
    

    ,然后跳过对bz.opaquebz.allocbz.free的分配。

  2. 您存储但没有真正检查BZ2_bzCompressInit调用的返回值。最终它确实会在内部while循环的条件下进行测试,但是您不会在其中检测到错误条件,而只会检测到成功条件和正常完成条件。

  3. 您对输入缓冲区的处理存在严重缺陷。

    • 首先,您错误地设置了可用输入字节数:

      bz.avail_in = sizeof(buf_read);
      

      由于您正在使用fgets()将数据读入缓冲区,因此在任何情况下输入数据都不会占用缓冲区的全部大小,因为fgets()确保将字符串终止符写入到缓冲区中。数组。实际上,情况可能更糟,因为fgets()将在换行符之后停止,因此成功读取后它可能只提供一个输入字节。

      如果您想坚持使用fgets(),则需要使用strlen()来确定每次读取的可用字节数,但是我建议您改用fread(),这样可以更可靠地填充缓冲区,并用其返回值指示已读取多少字节,并正确处理包含空字节的输入。

    • 第二, 您使用BZ2_bzCompress()压缩每个输入缓冲区,就好像它是一个完整文件一样 。当到达缓冲区末尾时,完成压缩运行并重新初始化bz_stream。这肯定会干扰解压缩,并且可以解释为什么您的程序(似乎)仅压缩其输入的第一行。您应该先阅读文件的全部内容(以适当大小的块为单位),然后在完成之前将所有内容提供给BZ2_bzCompress(... BZ_RUN)。对于整个文件(而不是每行),应该有一个对BZ2_bzCompress(... BZ_FINISH)的调用序列,最后应该对BZ2_bzCompressEnd()进行一个调用。

  4. 您不会对任何对标准库或bzip函数的调用执行错误检测或处理。您确实可以处理其中某些预期的成功案例返回值,但也需要重新分隔错误。

  5. 还有一些奇怪的地方

    • 您有未使用的变量nbytes_innbytes_outbzerrorb
    • 您将输入文件打开为 text 文件,尽管是否有所不同取决于平台。
    • ftell() / fseek()对除了设置save_pos之外没有其他整体效果。
    • 尽管这不是有害的,但在每一行的末尾(或初始)将输出缓冲区memset()设为全零也是无用的
    • 鉴于您正在压缩输入,因此提供的输出缓冲区是输入缓冲区的六倍,这很奇怪(但同样没有害处)。