функция ftell, дающая -1 в C для стандартного вывода

#c #popen

#c #popen

Вопрос:

Я хочу wget на C, и я использую popen для этого.

 FILE *stdoutPtr = popen(command,"r");
fseek(stdoutPtr, 0L, SEEK_END);
long pos = ftell(stdoutPtr);
  

Здесь я хочу получить размер stdout , чтобы я мог инициализировать буфер. Но pos переменная всегда равна -1.
pos предполагается, что она сообщает мне текущую позицию указателя чтения.

Пожалуйста, помогите….

Комментарии:

1. ftell — это функция ввода-вывода для определения текущей позиции в потоке. -1 указывает на ошибку. Вы можете прочитать точную ошибку, используя perror и глобальную errno .

Ответ №1:

FILE Возвращаемый by popen — это не обычный файл, а вещь, называемая a pipe . (Это то, что p означает.) Данные проходят через канал из стандартного вывода команды, которую вы вызвали в своей программе. Поскольку это канал связи, а не файл на диске, канал не имеет определенного размера, и вы не можете искать разные местоположения в потоке данных. Следовательно, fseek и ftell оба будут терпеть неудачу при применении к this FILE , и это то, что -1 означает возвращаемое значение. Если вы проверите errno сразу после вызова ftell , вы обнаружите, что оно имеет значение ESPIPE , что означает «Вы не можете сделать это с каналом».

Если вы пытаетесь прочитать весь вывод из команды в один char* буфер, единственный способ сделать это — многократно вызывать одну из функций чтения, пока она не укажет конец файла, и при необходимости увеличивать буфер с помощью realloc . Если выходные данные потенциально велики, было бы лучше изменить вашу программу для обработки данных порциями, если есть какой-либо способ сделать это.

Комментарии:

1. «fseek и ftell оба завершатся ошибкой при применении к этому ФАЙЛУ, и это то, что означает возвращаемое значение -1» — любая авторитетная цитата по этому поводу (например, C или другой стандарт)?

2. @pfalcon — это текст под ОШИБКАМИ в pubs.opengroup.org/onlinepubs/9699919799/functions/fseek.html что вы ищете? (Обратите внимание, что написано в «[ESPIPE]».)

3. И я надеюсь, что feof() работает, как и ожидалось, с файлами popen () ed: pubs.opengroup.org/onlinepubs/009695399/functions/feof.html не дает никаких исключений, и из описания это будет работать следующим образом: когда fread() возвращает 0 для EOF , он устанавливает флаг EOF в ФАЙЛЕ, а feof() просто возвращает это, поэтому эта обработкадействительно не зависит от канала.

Ответ №2:

Вы не можете использовать каналы таким образом. Во-первых, информация устареет в тот момент, когда вы ее получите, поскольку к тому времени в канал может быть записано больше данных. Вы должны использовать другую стратегию распределения.

Наиболее распространенной стратегией является выделение буфера фиксированного размера и просто продолжайте чтение, пока не дойдете до конца файла. Вы можете обрабатывать данные по мере их чтения, если хотите.

Если вам нужно обработать все данные в одном блоке, вы можете выделить большой буфер и начать чтение в него. Если он заполняется, используйте realloc для увеличения буфера и продолжайте, пока не получите все.

Общим шаблоном является сохранение указателя буфера, количества буферов и размера выделения. Изначально установите размер выделения, скажем, 64 КБ. Установите счетчик равным нулю. Выделите буфер объемом 64 КБ. Считайте до size-count байтов в буфер. Если вы нажмете EOF, остановитесь. Если буфер почти заполнен, увеличьте размер выделения на 50% и realloc буфер.