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的字符数。

虽然真的,你应该使用fgetsgetline或类似的面向文本的函数来读取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); 

下面是使用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的两个size参数也很重要,你必须让它fread阅读。 请注意,在popen的情况下,如果进程退出而没有给出任何输出,则fread将仅返回0。 如果进程打印任何内容需要很长时间,它将不会返回0。

如果输出大于BUFSIZ ,则可以使用while循环包装fread