使用 read() 函数时检查 EOF
Posted
技术标签:
【中文标题】使用 read() 函数时检查 EOF【英文标题】:Checking for EOF when using read() function 【发布时间】:2014-07-24 18:56:37 【问题描述】:这是我第一次从文件描述符中读取,我已经通过反复试验进行了大约 3 个小时的测试,我几乎让我的阅读器工作了!我只需要一点帮助来检查命名管道上的 EOF。
好的,我正在打开一个(多个)命名管道,如下所示:
fds[j].fd = open(pipeNameo, O_RDWR) ; // storing it into my file descriptor array
然后我正在轮询命名管道以查看是否有任何东西通过(轮询在循环内):
int ret = poll(fds, numOfPipesUsed, timeout_msecs);
当某些事情发生时,我通过将写入的文件描述符发送到此函数来处理文件:
int processFileDes( int fd )
char buf[10] ;
read(fd, buf, 1) ;
char curr = buf[0] ;
while (curr != EOF)
if ( curr == ' ')
// do nothing it is a space
else if ( curr == '\n')
printf("NEW LINE!\n") ;
else
int num = curr - '0' ; // turns char number into an int
printf("Curr Num: %d\n", num) ;
printf("BEFORE\n"); // Gets stuck here when EOF, this is the string of output
read(fd, buf, 1) ;
printf("AFTER\n") ;
curr = buf[0] ;
printf("Success!\n") ; // this is never printed
return 0 ;
一切正常,除了 read()
函数在读取完所有字符后会卡住(我想是在等待返回)。应该是 EOF。我需要能够检查 EOF。
我尝试了一种解决方法,通过计算读取的字符数(因为我知道输入的大小)来阻止我的程序读取,并且它会起作用,唯一的问题是在最后一个字符之后有空格时导致我的循环轮询返回 1 并在剩余的待读取空间(无效输入)上再次运行 processFile()
。
请帮忙:')
输入只是一个数字矩阵,如下所示:
0 1 1
2 0 3
1 0 0
【问题讨论】:
【参考方案1】:您应该首先确保您实际上是在管道上到达文件末尾。
当您打开一个 FIFO(命名管道的另一个名称)进行读取时,该进程将等待直到另一个进程打开它进行写入并写入一些内容。然后它将继续等待更多输入,直到 所有 将其打开以进行写入的进程都将其关闭。
您可以使用mkfifo
和cat
在几个终端窗口中进行测试:
$ mkfifo test-fifo
$ cat test-fifo # This is the reading process and will wait for data to read
在另一个终端:
$ cat > test-fifo # This is the writing process; type here and see it above
现在如果你关闭写入进程,读取进程将退出,因为它已经到达文件末尾。
但是,如果你打开两个写进程,只退出一个,FIFO 会保持打开状态,读端不会结束,直到你都关闭它们。
因此,一种很容易犯错误的可能性是,在某处仍然打开 FIFO 以进行写入,因此读取端永远不会遇到文件结束的情况。需要注意的一件事是,如果该进程本身也打开了 FIFO 以供写入,或者生成数据的任何进程只是保持管道打开而不是在完成后关闭它。
如果您无法确定某个进程是否打开了管道以供写入,请尝试fuser
或lsof
来识别任何可能打开它的进程。
您的代码中的其他一些 cmets,也可能是问题:
char buf[10] ;
read(fd, buf, 1) ;
char curr = buf[0] ;
while (curr != EOF)
这不是您使用低级、无缓冲read
原语确定是否到达文件末尾的方式;这就是您使用像fgetc
这样的缓冲stdio 操作的方法。使用read
,您可以使用所需的读取长度调用它,它会返回它可以读取的长度(可能小于您要求的长度),如果它在文件末尾,则返回 0,然后返回 -1关于错误。如果您没有检查read
的返回值,那么您有一个错误。请注意,并非所有错误都是致命的。
即使您使用的是fgetc
,这段代码也有问题。 fgetc
返回一个 int,而不是一个 char,因此它可以返回完整的字符值范围以及 EOF 的标记值。
printf("BEFORE\n"); // Gets stuck here when EOF, this is the string of output
read(fd, buf, 1) ;
printf("AFTER\n") ;
您通常不应该在两次轮询调用之间尝试读取相同的文件描述符两次;否则,如果文件描述符上没有更多可用数据,则第二个可能会阻塞。相反,您应该读取一定数量的数据,但要准备好read
返回的数据少于您请求的数据,然后返回轮询循环以找出现在可用的数据(可能在不同的 fd 上) ,如果这个没有可用的新数据,但另一个有)。
read
的使用方式一般是一次读取整个缓冲区,而不是一次读取一个字符。
【讨论】:
我以前从未听说过 fuser 和 lsof。此外,恕我直言,这是一个完美的总结和管道/fifo陷阱的提示。 +1 谢谢。【参考方案2】:您需要打开非阻塞,因为管道将等待数据可用:
fds[j].fd = open(pipeNameo, O_RDWR | O_NONBLOCK);
【讨论】:
【参考方案3】:读取的返回值 0 表示 EOF。
【讨论】:
问题是,一旦达到 EOF,它就永远不会返回。 read() 卡在循环的最后一次迭代中。 循环结束时的printf("AFTER\n")
永远不会打印最后的时间,这意味着 read() 在尝试读取并且已经是 EOF 时永远不会完成。
@DavidBaez 您的代码从不检查读取的返回值。此外,由于您正在从管道读取,因此在管道的另一端关闭之前您不会看到 EOF。有这种情况吗?
@DavidBaez 如果 read() 返回 0,则不应再次调用 read()。您的代码需要检查 read() 的返回值并处理返回值 0(EOF)和 -1(错误)。您还需要确保命名管道的另一端实际上是关闭的。在另一端关闭之前不会有 EOF。以上是关于使用 read() 函数时检查 EOF的主要内容,如果未能解决你的问题,请参考以下文章
read.csv 警告“引用字符串中的 EOF”阻止完整读取文件