C语言手册-read

名称:

pread,read-从文件读

语法:

#include <unistd.h>

ssize_t pread(int fildes, void *buf, size_t nbyte, off_t offset);
ssize_t read(int fildes, void *buf, size_t nbyte);

描述:

read()函数会尝试从fildes指定的文件描述符对应的文件中读取nbyte个字节,然后存放到buf中。同时对相同的管道、命名管道或终端设备的多个读取操作是未指定的

在下面描述的操作被执行之前,如果nbyte为0,read()函数会按照下面描述的方式检查并返回错误。如果没有错误,或者错误检测没有执行,read()会返回0没有进一步的结果

对于支持seek的文件(比如一个正常的文件),read()会从fildes中指定的偏移位置开始读取。偏移量会随着读取的字节数增长

对于不支持seek的文件(比如终端),始终从当前位置开始读。此种类型文件的偏移位置是未定义的

在当前文件结束位置之后不会进行任何数据的传输。如果起始位置在EOF及其之后都会导致read()函数返回0。如果文件是特殊设备文件,read()请求的结果是根据具体实现定义的

如果nbyte的值大于SSIZE_MAX,结果是根据定义实现的

当尝试从空管道或者空FIFO读取时:

  • 如果没有进程持有管道的写端,read()将返回0来指示EOF
  • 如果有进程持有写端,且O_NONBLOCK被置位,read()会返回-1并将errno设置为EAGAIN
  • 如果有进程持有写端,且O_NONBLOCK未被置位,read()会阻塞调用线程直到有数据被写入管道或者所有持有写端的进程被关闭

当尝试从一个支持非阻塞读的文件(非管道/匿名管道)读取,且当前没有数据可用时:

  • 如果O_NONBLOCK被置位,read()函数会返回-1并将errno设置为EAGAIN
  • 如果O_NONBLOCK没有置位,read()会阻塞调用线程直到有数据可用
  • O_NONBLOCK标志位的使用不会在有数据可用的时候产生影响

read()函数会从文件中读取之前写过的数据。如果文件EOF之前的数据还没有被写入,read()仍会返回数据但内容为0。例如,lseek()函数允许将偏移设置在当前已有数据之后的位置,随后就可以在这里写数据,在这两片数据之间的read()操作就会返回内容为0的数据

在函数成功执行之后,此时nbyte>0,read()会更新相关文件的最后数据获取时间戳,然后返回成功读取的字节数。返回的数字不会大于nbyte。返回值会在文件中剩余的字节少于nbyte个时小于nbyte,这种情况可能发生于read()请求被信号量打断、文件是管道/命名管道或者其他特殊文件在读取的时候立即可用的数据少于nbyte。比如,从和终端相关联的文件读取的数据可能就是一行字符

如果read()函数在读取任何数据之前被信号量打断,会返回-1并将errno设置为EINTR

如果read()函数在读取了一些数据之后被信号量打断,会返回成功读取的字节数

对于通常的文件,超过fildes指向的文件描述指定的最大偏移值的数据不会进行传输

如果fildes引用了socket,read()函数和没有设置flag的recv()相同

如果O_DSYNC和O_RSYNC被置位,在文件描述符上的读I/O操作将会按照同步I/O数据完整性的定义来完成;如果O_SYNC和O_RSYNC被置位,在文件描述符上的读I/O操作将会按照同步I/O文件完整性的定义来完成

如果fildes指向的是一个共享内存对象,读操作的结果将是未定义的

如果fildes指向的是一个类型内存对象,读操作的结果将是未定义的

从流文件读取的read()函数可以以三种模式读取数据:比特流模式、消息不保留模式、消息舍弃模式。默认是比特流模式。模式可以使用I_SRDOPT ioctl()请求修改,可以用I_GRDOPT ioctl()请求检测。比特流模式下,read()会尽可能多的从流中读取数据直到满足请求的数量或者流中没有数据,而忽视消息边界

在消息保留模式下,read()会尽可能多的读取数据直到满足请求或者达到消息边界。如果read()没有读取消息中所有的数据,剩下的数据仍会留在流中等待下一次读取。相反的,消息舍弃模式下,read()读取后消息中剩下的数据会被舍弃,后续如果有read()、getmsg()、getpmsg()也将无法读取到

read()处理0字节流的方式取决于当前的读取模式。字节流模式下,read()会持续读取数据直到满足nbyte个或者没有更多的数据或者遇到0字节消息阻塞。read()函数之后返回成功读取的字节数,并将0字节消息放回流中以待下一个read()、getmsg()、getpmsg()读取。在消息保留或消息舍弃模式下,遇到0字节消息之后将会返回0并将其从流中移除。如果0字节消息是流中读取的第一个消息,无论处于何种模式这个消息都会被舍弃并返回0

read()从流中读取数据的时候会返回流的头读取队列的最前面的消息,无论消息的优先级是什么

默认情况下,流是控制正常模式,在这种模式下read()只能从生成的消息中只包含数据而不包含控制部分的流文件。如果消息中包含了控制部分,read()就会失败。可以通过I_SRDOPT ioctl()命令改变默认的流模式为控制数据模式或者控制舍弃模式。在控制数据模式下,read()会将所有的控制部分转化为数据并在发送任何原生的数据部分之前将其发送。在控制舍弃模式下,read()会舍弃所有的控制部分

此外,如果在read()调用之前流的头就已经处理过一个异步错误,read()会失败。在这种情况下errno将不会反应read()的结果,而是反应之前的错误。如果read()读取的流出现了暂停,read()仍会继续执行直到流的头读取队列为空,然后返回0

pread()函数和read()函数基本一致,除了pread()会从给定的偏移位置读取而且不会改变偏移位置。pread()的第四个参数指定了偏移。如果指定了无法seek到的位置,蒋会导致错误

返回值:

在成功执行的情况下,这些函数会返回一个非负整数指明成功读取的字节数。否则函数会返回-1并设置errno指明错误

错误:

在下列情况下函数执行会失败:

EAGAIN:文件不是管道、命名管道、socket,文件描述符的O_NONBLOCK标志位被置位,读操作将会阻塞进程。

EBADF:fildes不是一个可用于打开并读取的文件描述符

EBADMSG:文件是流文件,而且待读取的消息中包含控制部分

EINTR:读操作被信号量中断,而且没有数据被传输

EINVAL:fildes指定的文件过着多路选择器是另一个多路选择器的下游

EIO:后台进程组的一个进程成员尝试从它的控制终端读取数据,而且调用线程关闭了SIGTTIN或者进程忽视了SIGTTIN或者进程所属的进程组是孤儿进程组。这个错误也可能因为具体实现定义的原因出现

EISDIR:fildes指向了一个目录,但是具体实现不允许read()或pread()读取目录。应该使用readdir()函数

EOVERFLOW:文件是正常文件,nbyte大于0,起始位置在EOF之前,但是起始位置大于或等于fildes指向的文件描述中指定的最大偏移值

pread()函数在下列情况下会失败:

EINVAL:指定的偏移量是负数,文件的偏移量将维持不变

ESPIPE:文件不支持seek

read()函数在下列情况下会失败:

EAGAIN:文件是管道或者命名管道,O_NONBLOCK标志位被置位,但是线程会被读操作阻塞

EAGAIN或EWOULDBLOCK:文件时socket,O_NONBLOCK被置位,但是线程会被读操作阻塞

ECONNRESET:尝试从一个被其上级强制关闭的socket读

ETIMEDOUT:尝试从socket中读的时候出现了超时

函数可能会在下列情况下失败:

EIO:物理I/O错误

ENOBUFS:系统资源不足以执行操作

ENOMEM:内存不足以支持操作

ENXIO:请求中含有不存在的设备,或者请求超出了设备的能力

posted @ 2018-12-14 18:01  biaoJM  阅读(950)  评论(0编辑  收藏  举报