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);
下面是使用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
。