Как получить доступный для чтения файловый дескриптор из источника потока байтов из сжатых файлов (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), когда вы все это сделаете!