C Язык: popen () с fread ()?

Я застрял на этом несколько дней, и это становится очень неприятно.

Я использую popen() для вызова процесса командной строки и получения его вывода и сохранения его в строке C. Я использовал fgets() но кажется, что ломается после новой строки, поэтому я использую fread() . Единственная проблема заключается в том, что возвращаемая строка C иногда перепуталась.

Вот мой код:

 const char *cmd = "date";//This the shell command char buf[BUFSIZ];//Output of the command FILE *ptr; int c; if ((ptr = popen(cmd, "r")) != NULL) while(fread(buf, sizeof(buf),1, ptr)) while ((c = getchar()) != EOF) printf("output = %s", buf); (void) pclose(ptr); 

Конечная строка C иногда содержит в ней странные символы, которых не должно быть, или иногда ни одна строка не доступна. Кто-нибудь может помочь? ):

Изменить: Вот что я делал при использовании fgets () Команда Shell может быть тем, что выводит текст. Не только «дата».

if ((ptr = popen(cmd, "r")) != NULL)
while (fgets(buf, BUFSIZ, ptr) != NULL)
printf("output = %s", buf);
(void) pclose(ptr);

Результат с date не включает символ '\0' (NUL), который необходимо для правильного завершения строки. Следите за количеством прочитанных символов и помещайте их в NUL самостоятельно.

Хотя на самом деле вы должны использовать функции fgets , getline или подобные текстовые функции для чтения из такой программы, как date . getline особенно прост (и безопасен, так как для вас требуется некоторое управление памятью):

 FILE *fp = popen("date", "r"); char *ln = NULL; size_t len = 0; while (getline(&ln, &len, fp) != -1) fputs(ln, stdout); free(ln); pclose(fp); 

Ну, fgets – это правильный способ сделать это.

 FILE *ptr; if (NULL == (ptr = popen(cmd, "r"))) { /* ... */ } while(fgets(buf, sizeof(buf), ptr) != NULL) { /* There is stuff in 'buf' */ } 

Я думаю, причина, по которой fgets не работала для вас, заключается в том, что вы делали что-то неправильно.

Теперь, вот почему я думаю, что у вас возникают проблемы с вашим текущим кодом:

  • Вы не проверяете, сколько действительно возвращено fread
  • Вы читаете с помощью getchar и отбрасываете материал
  • У вас нет терминатора NUL в буфере

Получите это правильно, и все будет лучше: fread может на законных основаниях читать меньше, чем вы сказали .

fread не добавляет терминатор NUL после того, что он читает. Вам нужно проверить возвращаемое значение, чтобы узнать, сколько он читает, и только печатать так много. Если вы читаете с помощью fread , вы обычно хотите записать данные с помощью fwrite , что-то в этом порядке:

 long bytes; while ((bytes=fread(buf, sizeof(buf), 1, ptr))>0) fwrite(buf, bytes, 1, stdout); 

Ниже приведен правильный способ использования fread для вывода процесса с помощью popen :

 const char *cmd = "date"; char buf[BUFSIZ]; FILE *ptr; if ((ptr = popen(cmd, "r")) != NULL) { /* Read one byte at a time, up to BUFSIZ - 1 bytes, the last byte will be used for null termination. */ size_t byte_count = fread(buf, 1, BUFSIZ - 1, ptr); /* Apply null termination so that the read bytes can be treated as a string. */ buf[byte_count] = 0; printf("%s\n", buf); } (void) pclose(ptr); 

Как вы можете видеть, основная проблема заключается в том, чтобы правильно обработать нулевое завершение. fread также параметр размера fread , вы должны позволить ему читать символ по характеру. Обратите внимание, что в случае popen , fread будет возвращать только 0, если процесс вышел, не выдавая никакого вывода. Он не вернет 0, если для процесса потребуется много времени.

Если выход больше BUFSIZ , вы можете обернуть fread с помощью цикла while.