来自stdin的read()

时间:2012-01-23 17:03:02

标签: c linux unix io

考虑以下代码行:

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 = 100stdin = ACtrl+D(即紧跟在单个字符后的EOF)。现在while loop会迭代多少次?

5 个答案:

答案 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)

  1. 读取尝试获取所有请求的字符。
  2. 如果在返回所有请求的字符之前发生EOF,它将返回它所获得的内容 在它执行此操作后,下一个读取返回-1,以告诉您文件结束。
  3. 尝试阅读时会发生什么,并且没有任何内容涉及阻塞。您可以调用open来读取阻塞或非阻塞的文件。 “阻止”意味着等到有东西返回。

    这是你在等待输入的shell中看到的。它坐在那里。直到你回来。

    非阻塞意味着如果没有,则read将不返回任何数据字节。根据许多其他因素会使完全正确的答案无法使用,read会将errno设置为EWOULDBLOCK,它可以让你知道为什么你的读取返回零字节。这不一定是致命的错误。

    您的代码可以测试减号以查找EOF或错误

答案 4 :(得分:0)

当我们说read是无缓冲的时,这意味着在从基础打开文件描述(这是一个潜在共享资源)中提取数据之后,在进程级别不会发生缓冲。如果stdin是终端,则可能至少有2个额外的缓冲区正在运行:

  1. 终端缓冲区,它可能会保留1-4k的数据,直到。
  2. 内核的cooked / canonical模式缓冲区,用于终端上的行输入/编辑,允许用户在线路上执行原始编辑(退格,后退,擦除行等),直到它被提交(到上述缓冲区)按Enter键。
  3. read将提取已经提交的内容,直到你传递给它的最大读取长度,但它不能从行编辑缓冲区中提取任何内容。如果要禁用此额外的缓冲层,则需要使用tcsetattr等查找如何为终端禁用cooked / canonical模式。