我正在从输入文件读取数据,并使用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);
}
答案 0 :(得分:1)
TL; DR:,但是有很多问题可以解释,您要解决的主要问题可能是您分别压缩文件的每一行,而不是整个文件
根据BZ2_bzCompressInit
的文档,bz_stream
参数应在调用之前分配并初始化。您的是(自动)分配的,但尚未(完全)初始化。更改为更清晰,更容易
bz_stream bz = { 0 };
,然后跳过对bz.opaque
,bz.alloc
和bz.free
的分配。
您存储但没有真正检查BZ2_bzCompressInit
调用的返回值。最终它确实会在内部while
循环的条件下进行测试,但是您不会在其中检测到错误条件,而只会检测到成功条件和正常完成条件。
您对输入缓冲区的处理存在严重缺陷。
首先,您错误地设置了可用输入字节数:
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()
进行一个调用。
您不会对任何对标准库或bzip函数的调用执行错误检测或处理。您确实可以处理其中某些预期的成功案例返回值,但也需要重新分隔错误。
还有一些奇怪的地方
nbytes_in
,nbytes_out
,bzerror
和b
。ftell()
/ fseek()
对除了设置save_pos
之外没有其他整体效果。memset()
设为全零也是无用的。