如何防止 fgets 阻塞当文件流没有新数据时

15

我有一个popen()函数,用于执行tail -f sometextfile命令。只要文件流中有数据,我就可以通过fgets()获取数据。但是,如果从 tail 中没有新的数据,fgets()就会挂起。我尝试过ferror()feof(),但都无济于事。如何确保fgets()在文件流中没有新数据时不尝试读取数据?

其中一个建议是使用select()函数。由于这是针对Windows平台的,因此选择操作似乎无法使用匿名管道(请参见此帖子)。

5个回答

31
在Linux(或任何类Unix的操作系统)中,您可以将popen()使用的底层文件描述符标记为非阻塞。
#include <fcntl.h>

FILE *proc = popen("tail -f /tmp/test.txt", "r");
int fd = fileno(proc);

int flags;
flags = fcntl(fd, F_GETFL, 0);
flags |= O_NONBLOCK;
fcntl(fd, F_SETFL, flags);

fgets函数如果没有输入可用,则会返回NULL,并将errno设置为EWOULDBLOCK。


15

fgets() 是一个阻塞读取函数,如果没有数据,它会等待直到有数据可用。

您需要使用 select()poll()epoll() 进行异步 I/O 操作,并在有数据可用时从文件描述符执行读取操作。

这些函数使用 FILE* 句柄的文件描述符进行操作,可通过以下方法获取: int fd = fileno(f);


1
一定要使用select() - 如果你有一个FILE *并且需要一个文件描述符,请使用fileno()。如果你有一个文件描述符并且需要一个FILE *,请使用fdopen()。 - plinth
很遗憾,我认为在Windows下select()在管道上无法工作。 - Roddy
2
混合使用select()和fgets()是危险的。FILE*包含select()不知道的内部缓冲区。正确的答案是O_NONBLOCK。 - Alcaro

0

如果你使用POSIX函数进行IO,而不是C库的函数,那么你可以使用selectpoll


0

你可以尝试使用低级IO函数(如open(),read()等)来读取sometextfile,就像tail本身所做的那样。当没有更多内容可读时,read()会返回零,但仍会在下一次尝试读取更多内容,这与FILE*函数不同。


这只是一个例子。思路是获取数据并将其通过互斥对象传递到 Flash 实例。 - SinisterDex

0

2
如果您自己解决了问题,请将其设置为答案,并可能发布您的解决方案。 - Jared Burrows

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接