#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
буфер.