文件表
进程控制块(PCB): 用来描述进程信息和相关资源,使用一个struct
来描述
在这个struct
中存在一个数组成员struct file* filp[NR_OPEN)
struct file
结构如下:
struct file {
unsigned short f_mode;// 文件权限
unsigned short f_flags;// 文件状态
unsigned short f_count;// 引用计数
struct m_inode* f_inode;// 文件在磁盘上的位置信息
off_t f_pos;// 偏移量
}
filp
数组的索引即为文件描述符,对用的元素为一个struct file
类型的文件表指针
f_count
: 当f_count
== 0时,才真正关闭文件
dup2
函数可以让两个不同的描述符指向同一个文件表
int dup2(int oldfd, int newfd) {
// ...
close(newfd);
filp[newfd] = filp[oldfd];
filp[newfd]->count++;
// ...
return 0;
}
dup
函数只接受一个oldfd
参数,返回值为新分配的描述符
f_pos
: 文件偏移量
lseek
函数修改文件偏移量f_pos
off_t lseek(int fd, off_t offset, int whence);
改变filp[fd]
指向的文件表struct file
结构体中f_pos
成员.
open
函数打开的文件f_pos
默认为0.
whence
表示基准值,offset
表示偏移大小
whence
等于SEEK_SET,起始位置,f_pos = 0 + offset
whence
等于SEEK_CUR,当前位置,f_pos = f_pos + offset
whence
等于SEEK_WHENCE,文件末尾,f_pos = 文件长度 + offset
非阻塞IO
以非阻塞方式打开一个文件
int fd = open("/dev/tty", O_RDONLY | O_NONBLOCK);
非阻塞read
,如果没有数据到来,返回-1.
此时需要通过全局变量errno
来判断是出错还是没有数据可读,如果errno
为E_WOULDBLOCK或E_AGAIN,表示当前没有数据可读.
使用fcntl
函数设置文件非阻塞标志
int fcntl(int fd, int cmd = F_GETFL); // 获取文件标志位
int fcntl(int fd, int cmd = F_SETFL, int arg); // 设置文件标志位
int fd = open("/dev/tty", O_RDWR);
int flags = fcntl(fd, F_GETFL);
flags |= O_NONBLOCK;
fcntl(fd, F_SETFL, flags);