考虑以下代码行:
while((n = read(STDIN_FILENO, buff, BUFSIZ)) > 0)
根据我的理解read/write
函数是非缓冲I / O的一部分。那么这意味着read()
函数每次调用stdio时只能读取一个字符吗?或者换句话说,n的值将是
-1 in case of error
n = 0 in case of EOF
1 otherwise
如果不是这种情况,上述read()
函数什么时候会返回?为什么?
注意:我还在考虑read()
将等到成功从stdin读取BUFSIZ
个字符数。但是在一个案例中可以读取的字符数少于BUFSIZ
?将永远等待或直到EOF到达(Ctrl + D
在unix上或Ctrl + Z
在Windows上)?
另外,让我们说BUFSIZ = 100
和stdin = ACtrl+D
(即紧跟在单个字符后的EOF)。现在while loop
会迭代多少次?
答案 0 :(得分:18)
read()的行为方式取决于正在读取的内容。对于常规文件,如果您要求N个字符,如果可用,则获得N个字符,如果文件末尾介入,则小于N.
如果read()正在以规范/熟化模式从终端读取,则tty驱动程序一次提供一行数据。因此,如果你告诉read()获得3个字符或300个,读取将挂起,直到tty驱动程序看到换行符或终端定义的EOF键,然后read()将返回行中的字符数或者您请求的字符数,以较小者为准。
如果read()从非规范/原始模式的终端读取,则读取将立即访问按键。如果你要求read()获得3个字符,它可能会返回0到3个字符,具体取决于输入时间和终端的配置方式。
read()在信号面前表现不同,返回时小于请求的字符数,如果信号在任何字符到达之前中断读取,则errno设置为EINTR为-1。
如果为非阻塞I / O配置了描述符,则read()的行为会有所不同。如果没有立即可用的输入,read()将返回-1,并将errno设置为EAGAIN或EWOULDBLOCK。这适用于套接字。
正如您所看到的,当您调用read()时,您应该准备好迎接惊喜。你不会总是得到你请求的字符数,并且你可能会得到像EINTR这样的非致命错误,这意味着你应该重试read()。
答案 1 :(得分:4)
您的代码为:
while((n = read(0, buff, BUFSIZ) != 0))
这是有缺陷的 - 括号表示它被解释为:
while ((n = (read(0, buff, BUFSIZ) != 0)) != 0)
在赋值之前计算布尔条件,因此n
只能获得值0(条件不为真)和1(条件为真)。
你应该写:
while ((n = read(0, buff, BUFSIZ)) > 0)
这会在EOF或读取错误时停止,n
会让您知道遇到的情况。
显然,上面的代码是问题中的拼写错误。
无缓冲I / O将读取您读取的字符数(但不会更多)。由于EOF或错误,它可能读取较少。它也可能读得少,因为在通话时可用的数量较少。考虑一个终端;通常情况下,这只会读到行尾,因为没有更多可用的行。考虑一个管道;如果馈送过程产生了128个未读字节,那么如果BUFSIZ是4096,则只能从读取中获得128个字节。非阻塞文件描述符可能会返回,因为没有可用的东西;套接字可能返回更少的字节,因为还没有更多的信息可用;磁盘读取可能返回更少的字节,因为执行读取时文件中剩余的字节数少于所请求的字节数。
但是,一般情况下,如果请求多个字节,read()
将不会返回一个字节。
答案 2 :(得分:2)
正如read()
联机帮助页所述:
返回值
成功时,返回读取的字节数(零表示文件结束),文件位置按此编号前进。如果此数字小于请求的字节数,则不是错误;这可能发生在例如因为现在实际可用的字节数较少(可能是因为我们接近文件结尾,或者因为我们正在从管道或终端读取),或者因为read()被中断了信号。出错时,返回-1,并正确设置errno。在这种情况下,未指定文件位置(如果有)是否发生变化。
因此,每个read()
将读取最多指定字节数;但它可能读得少。 “非缓冲”表示如果指定read(fd, bar, 1)
,则read只读取一个字节。缓冲IO尝试读取BUFSIZ
的量子,即使您只需要一个字符。这可能听起来很浪费,但它避免了系统调用的开销,这使得它很快。
答案 3 :(得分:0)
尝试阅读时会发生什么,并且没有任何内容涉及阻塞。您可以调用open来读取阻塞或非阻塞的文件。 “阻止”意味着等到有东西返回。
这是你在等待输入的shell中看到的。它坐在那里。直到你回来。
非阻塞意味着如果没有,则read将不返回任何数据字节。根据许多其他因素会使完全正确的答案无法使用,read会将errno设置为EWOULDBLOCK,它可以让你知道为什么你的读取返回零字节。这不一定是致命的错误。
您的代码可以测试减号以查找EOF或错误
答案 4 :(得分:0)
当我们说read
是无缓冲的时,这意味着在从基础打开文件描述(这是一个潜在共享资源)中提取数据之后,在进程级别不会发生缓冲。如果stdin
是终端,则可能至少有2个额外的缓冲区正在运行:
read
将提取已经提交的内容,直到你传递给它的最大读取长度,但它不能从行编辑缓冲区中提取任何内容。如果要禁用此额外的缓冲层,则需要使用tcsetattr
等查找如何为终端禁用cooked / canonical模式。