Как получить доступный для чтения файловый дескриптор из источника потока байтов из сжатых файлов (gz)

Я новичок в программировании на Си. Я использовал библиотеку, которая требует файловый дескриптор из источника потока байтов. Это прекрасно работает, когда у меня есть обычные файлы. Тем не менее, у меня есть входные данные GZ файлов. Общий объем сжатых данных, которые мне нужно проанализировать, составляет около 5 ТБ. У меня недостаточно места, чтобы распаковать их все.

Я использовал следующие два метода, но они, кажется, не работают,

input = gzopen (argv[i], "r");

Второй способ

  arg = argv[1];
  cmd = malloc(sizeof(prefix) + strlen(arg) + 1);
  if (!cmd) {
       fprintf(stderr, "%s: malloc: %s\n", argv[i], strerror(errno));
        return 1;
    }
   sprintf(cmd, "%s%s", prefix, arg);
   input =  popen(cmd, "r");

Я был бы признателен, если бы любая помощь может быть предоставлена.

Заранее спасибо.

1 ответ

Решение

Здесь я сделаю вывод, что вы не показываете прототип библиотечной функции, которую вы используете, но в комментарии вы говорите, что это работает для вас, когда файл не сжат:

fd = open(argv[i], O_RDONLY);

но использование gzopen() или popen() не позволяет. Итак, я понял, что используемая библиотечная функция принимает аргумент дескриптора файла и считывает и интерпретирует сами данные.

Это приводит к тому, что ваша непосредственная проблема должна быть: open () возвращает дескриптор файла "int", а gzopen() и popen() - нет.

Документация zlib определяет gzopen() следующим образом:

ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode));

Таким образом, он возвращает пользовательский тип дескриптора файла "gzFile"; Вы не можете передать это функции, которая планирует выполнить read(), ожидая дескриптор файла int.

Аналогично, popen() возвращает дескриптор файла FILE* stdio, а не тип int, и передача его чему-то, ожидающему int, также не будет работать.

Поэтому, если вы хотите использовать zlib, вам придется использовать собственную функцию gzread(), а затем передавать данные, которые вы читаете, в библиотечную функцию через дескриптор типа int, возможно, через канал. Это было бы обременительно.

Ваша лучшая ставка может заключаться в использовании popen(), как вы пытались, но используйте функцию stdio fileno(), чтобы получить дескриптор int, лежащий в основе FILE*, и передать его в библиотечную функцию.

Таким образом, предполагая, что префикс в вашем исходном коде был чем-то вроде "gzip -dc ", команды, которая будет передавать распакованные данные из вашего файла в stdout, мы могли бы изменить ваш код на что-то вроде этого (также вы присвоили arg значение 'argv[1]'но использовал'argv[i]'в другом месте - я предполагаю, что'1'была опечаткой):

  char *prefix, *arg, *cmd;
  FILE *pinput;
  int fd;

  prefix = "gzip -dc ";
  arg = argv[i];
  cmd = malloc(strlen(prefix) + strlen(arg) + 1);
  if (!cmd) {
       fprintf(stderr, "%s: malloc: %s\n", argv[i], strerror(errno));
        return 1;
    }
   sprintf(cmd, "%s%s", prefix, arg);
   pinput =  popen(cmd, "r");
   fd = fileno(pinput);

Тогда вы сможете передать 'fd' в библиотечную функцию и заставить ее работать так же, как и с несжатыми данными.

И не забудьте освободить (cmd), когда вы все это сделаете!

Другие вопросы по тегам