我已经在这个问题上坚持了几天了,这真的很令人沮丧。
我正在使用
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);
fread
不会在读取的内容后插入 NUL 终止符。您需要检查返回值以了解读取了多少内容,并且仅打印该内容。如果您使用 fread
进行读取,您通常希望使用 fwrite
写入数据,按以下顺序:
long bytes;
while ((bytes=fread(buf, sizeof(buf), 1, ptr))>0)
fwrite(buf, bytes, 1, stdout);
嗯,
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
与 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
的第二个参数必须为1)。
请注意,在
popen
的情况下,如果进程退出且没有给出任何输出,则 fread
只会返回 0。如果进程需要很长时间才能打印任何内容,它不会返回 0。
如果输出大于 BUFSIZ
,您可以用
fread
循环包裹
while
。
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);