繁体   English   中英

从stdin读取()

[英]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 = 100stdin = 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量子,即使您只想要一个字符也是如此。 这听起来很浪费,但它避免了进行系统调用的开销,从而使调用速度更快。

  1. 读取尝试以获取所有要求的字符。
  2. 如果EOF发生在可以返回所有请求的字符之前,则它返回在下一次读取返回-1之后执行的操作,以使您知道文件结尾。

当它尝试读取并且什么也没有发生时,会发生什么事情,称为阻塞。 您可以调用open来读取文件是否被阻止。 “阻塞”是指等到有东西返回。

这就是您在shell中等待输入的内容。 它坐在那里。 直到您点击返回。

非阻塞意味着如果没有字节,读取将不返回数据字节。 取决于许多其他因素,这些因素将使您无法使用完全正确的答案,因此read会将errno设置为EWOULDBLOCK之类的东西,它使您知道为什么读取返回零字节。 这不一定是致命错误。

您的代码可以测试是否为负以找到EOF或错误

当我们说read是无缓冲的时,这意味着从基础打开文件描述(可能是共享的资源)中提取数据之后,在您的处理级别没有缓冲发生。 如果stdin是终端,则可能至少有2个其他缓冲区在播放,但是:

  1. 终端缓冲区,可能直到脱机为止一直保存1-4k的数据。
  2. 内核的熟模式/规范模式缓冲区,用于在终端上进行行输入/编辑,这使用户可以在行上执行原始编辑(退格,后退字,擦除行等),直到通过按Enter将其提交(提交至上述缓冲区)为止。

read将拉取已提交的所有内容,直到达到传递给它的最大读取长度,但它不能从行编辑缓冲区中拉取任何内容。 如果要禁用此额外的缓冲层,则需要查找如何使用tcsetattr等为终端禁用熟模式/规范模式。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM