我写这篇文章的目的是为了对read和write两个函数的用法做一个总结,同时提醒自己不要忘记:
一、原型介绍
#include <unistd.h>
ssize_t read(int
fd, void *buf, size_t count);
参数:
fd: 将要读取数据的文件描述词。
buf: 所读取到的数据的内存缓冲。
count: 需要读取的数据量。
read()会把参数fd所指的文件传送nbyte个字节到buf指针所指的内存中。若参数nbyte为0,则read()不会有作用并返回0。返回值为实际读取到的字节数,如果返回0,表示已到达文件尾或无可读取的数据。错误返回-1,并将根据不同的错误原因适当的设置错误码。
EAGAIN:打开文件时设定了O_NONBLOCK标志,并且当前没有数据可读取
EBADF:文件描述词无效,或者文件不可读
EFAULT:参数buf指向的空间不可访问
EINTR:数据读取前,操作被信号中断
EINVAL:一个或者多个参数无效
EIO:读写出错
EISDIR:参数fd索引的时目录
二、read和write的正确用法
①不完善的用法一:
int ret = read(fd, buf, len);
if(ret == -1){
exit(-1);
}else if(ret == 0){
close(fd);
}
忽略了 errno 的处理. 仔细看文档, 函数返回 -1 不能完全代表 fd 错误, 还需要结合 errno。
②不完善用法二:
int ret = read(fd, buf, len);
if(ret == -1){
if(errno == EINTR){
// 怎么办?
}else if(errno == EAGAIN){
// 怎么办
}
exit(-1);
}else if(ret == 0){
close(fd);
}
EINTR 表示 read() 函数调用被系统中断了, 调用者和 fd 都没有问题, 有问题的是操作系统。而
EAGAIN 是在非阻塞 IO 时会出现. 上面的代码判断了 errno, 但不知道下一步该怎么做, 还不行。
③正确用法
while(1){
int ret = read(fd, buf, len);
if(ret == -1){
if(errno == EINTR){
continue;
}else if(errno == EAGAIN){
// 根据你和调用者的约定, 返回一个数值告诉它再次重试
// 一般是结合 select/epoll 等 IO 多路复用函数
}
exit(-1);
}else if(ret == 0){
close(fd);
}
// proc
break;
}
write函数也有类似用法。