[英]read() from stdin
考虑以下代码行:
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到达(unix上的Ctrl + D
或Windows上的Ctrl + Z
)?
另外,假设BUFSIZ = 100
, stdin = ACtrl+D
(即紧随单个字符之后的EOF)。 现在, while loop
将迭代多少次?
read()的行为方式取决于所读取的内容。 对于常规文件,如果要求输入N个字符,则可以得到N个字符(如果可用的话),如果少于文件末尾,则得到N个字符。
如果read()正在以规范/烹饪模式从终端读取,则tty驱动程序一次提供一行数据。 因此,如果您告诉read()获得3个字符或300个字符,则read将挂起,直到tty驱动程序看到换行符或终端定义的EOF键为止,然后read()将返回该行中的字符数或您请求的字符数,以较小者为准。
如果read()正在以非规范/原始模式从终端读取,则read将立即访问按键。 如果要求read()获得3个字符,则可能会返回0到3个字符,具体取决于输入时间和终端的配置方式。
read()面对信号的行为会有所不同,返回的字符数少于请求的数量,如果信号在任何字符到达之前中断了读取,则返回的值少于-1,而errno设置为-1。
如果已将描述符配置为非阻塞I / O,则read()的行为将有所不同。 如果没有立即可用的输入,read()将返回-1,并将errno设置为EAGAIN或EWOULDBLOCK。 这适用于套接字。
如您所见,当您调用read()时,应该已经准备好感到惊讶。 您将不会总是获得所需的字符数,并且可能会遇到非致命错误,例如EINTR,这意味着您应重试read()。
您的代码显示为:
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()
不会仅返回一个字节。
如read()
页所述:
返回值
成功后,将返回读取的字节数(零表示文件末尾),并且文件位置以该数字前移。 如果此数目小于请求的字节数,这不是错误; 例如,这可能是因为当前实际可用的字节较少(可能是因为我们接近文件末尾,或者因为我们正在从管道或终端读取),或者因为read()被a中断了。信号。 如果出错,则返回-1,并正确设置errno。 在这种情况下,未指定文件位置(如果有)是否更改。
因此,每个read()
最多可以读取指定字节数; 但它可能读得更少。 “非缓冲”表示如果指定read(fd, bar, 1)
,则read只会读取一个字节。 缓冲的IO尝试读入BUFSIZ
量子,即使您只想要一个字符也是如此。 这听起来很浪费,但它避免了进行系统调用的开销,从而使调用速度更快。
当它尝试读取并且什么也没有发生时,会发生什么事情,称为阻塞。 您可以调用open来读取文件是否被阻止。 “阻塞”是指等到有东西返回。
这就是您在shell中等待输入的内容。 它坐在那里。 直到您点击返回。
非阻塞意味着如果没有字节,读取将不返回数据字节。 取决于许多其他因素,这些因素将使您无法使用完全正确的答案,因此read会将errno设置为EWOULDBLOCK之类的东西,它使您知道为什么读取返回零字节。 这不一定是致命错误。
您的代码可以测试是否为负以找到EOF或错误
当我们说read
是无缓冲的时,这意味着从基础打开文件描述(可能是共享的资源)中提取数据之后,在您的处理级别没有缓冲发生。 如果stdin
是终端,则可能至少有2个其他缓冲区在播放,但是:
read
将拉取已提交的所有内容,直到达到传递给它的最大读取长度,但它不能从行编辑缓冲区中拉取任何内容。 如果要禁用此额外的缓冲层,则需要查找如何使用tcsetattr
等为终端禁用熟模式/规范模式。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.