我有一个由一定数量的 bzip2 文件组成的串联文件。我还知道该文件中各个 bzip2 块的大小。

我想从单个 bzip2 数据块中解压缩 bzip2 流,并将输出写入标准输出。

首先,我使用 fseek 将文件光标移动到所需的存档字节,然后将文件的“大小”-chunk 读入 BZ2_bzRead 调用:

int headerSize = 1234;
int firstChunkSize = 123456;
FILE *fp = fopen("pathToConcatenatedFile", "r+b");
char *bzBuf = malloc(sizeof(char) * firstChunkSize);
int bzError, bzNBuf;
BZFILE *bzFp = BZ2_bzReadOpen(&bzError, *fp, 0, 0, NULL, 0);

# move cursor past header of known size, to the first bzip2 "chunk"
fseek(*fp, headerSize, SEEK_SET);

while (bzError != BZ_STREAM_END) {
    # read the first chunk of known size, decompress it
    bzNBuf = BZ2_bzRead(&bzError, bzFp, bzBuf, firstChunkSize);
    fprintf(stdout, bzBuf);
}

BZ2_bzReadClose(&bzError, bzFp);
free(bzBuf);
fclose(fp);

问题是,当我将 fprintf 语句的输出与在命令行上运行 bzip2 的输出进行比较时,我得到两个不同的答案。

具体来说,与在命令行上运行 bzip2 相比,我从这段代码中得到的输出更少。

更具体地说,我从这段代码中得到的输出是命令行过程输出的一个较小的子集,而且我缺少感兴趣的 bzip2 块的尾端的内容。

我已经通过另一种技术验证了命令行 bzip2 提供了正确的答案,因此,我的 C 代码的一些问题导致块末尾的输出丢失。我只是不知道那是什么问题。

如果您熟悉 bzip2libbzip2 ,您能否就我在上面的代码示例中做错了什么提供任何建议?感谢您的建议。

最佳答案

这是我的源代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <bzlib.h>

int
bunzip_one(FILE *f) {
  int bzError;
  BZFILE *bzf;
  char buf[4096];

  bzf = BZ2_bzReadOpen(&bzError, f, 0, 0, NULL, 0);
  if (bzError != BZ_OK) {
    fprintf(stderr, "E: BZ2_bzReadOpen: %d\n", bzError);
    return -1;
  }

  while (bzError == BZ_OK) {
    int nread = BZ2_bzRead(&bzError, bzf, buf, sizeof buf);
    if (bzError == BZ_OK || bzError == BZ_STREAM_END) {
      size_t nwritten = fwrite(buf, 1, nread, stdout);
      if (nwritten != (size_t) nread) {
        fprintf(stderr, "E: short write\n");
        return -1;
      }
    }
  }

  if (bzError != BZ_STREAM_END) {
    fprintf(stderr, "E: bzip error after read: %d\n", bzError);
    return -1;
  }

  BZ2_bzReadClose(&bzError, bzf);
  return 0;
}

int
bunzip_many(const char *fname) {
  FILE *f;

  f = fopen(fname, "rb");
  if (f == NULL) {
    perror(fname);
    return -1;
  }

  fseek(f, 0, SEEK_SET);
  if (bunzip_one(f) == -1)
    return -1;

  fseek(f, 42, SEEK_SET); /* hello.bz2 is 42 bytes long in my case */
  if (bunzip_one(f) == -1)
    return -1;

  fclose(f);
  return 0;
}

int
main(int argc, char **argv) {
  if (argc < 2) {
    fprintf(stderr, "usage: bunz <fname>\n");
    return EXIT_FAILURE;
  }
  return bunzip_many(argv[1]) != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
  • 我非常关心正确的错误检查。例如,在尝试访问缓冲区之前,我确保 bzErrorBZ_OKBZ_STREAM_END。文档清楚地表明,对于 bzError 的其他值,返回的数字是未定义的。
  • 大约 50% 的代码与错误处理有关,这应该不会吓到您。应该是这样。到处都是错误。
  • 代码还是有一些bug。如果出现错误,它不会正确释放资源( fbzf )。

  • 这些是我用于测试的命令:
    $ echo hello > hello
    $ echo world > world
    $ bzip2 hello
    $ bzip2 world
    $ cat hello.bz2 world.bz2 > helloworld.bz2
    $ gcc -W -Wall -Os -o bunz bunz.c -lbz2
    $ ls -l *.bz2
    -rw-r--r-- 1 roland None 42 Oct 12 09:26 hello.bz2
    -rw-r--r-- 1 roland None 86 Oct 12 09:36 helloworld.bz2
    -rw-r--r-- 1 roland None 44 Oct 12 09:26 world.bz2
    $ ./bunz.exe helloworld.bz2
    hello
    world
    

    关于c - 如何使用 C 从 bzip2 存档中提取所有数据?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/3912157/

    10-10 11:28