1 文件模型
1.1 文件描述符(file descriptor)
在unix及相关系统中,文件描述符(以下简称FD)是一个抽象的指针,指向某个特定的I/O资源(I/O资源指文件、网络读写、管道等),系统通过此FD进行I/O操作。FD是一个非负整数,在C语言使用一个int表示。
每个非守护进程在启动时,有三个默认FD是0(stdin)、1(stdout)、2(stderr)。
进程运行中,每开启一个文件,就从进程维护的FD表里找最小未被使用的数字,作为此文件的FD。
1.2 进程与文件描述符的关系
此处用linux实现来解释上图的unix三级模型:
- 进程表(proc_list):unix系统实时维护了一张进程表(命名为proc_list对象),表中每一项元素表示了此进程的相关状态,用task_struct类型表达;
- 进程状态(task_struct):进程状态中有一属性定义为
struct file * filp[NR_OPEN]
,记录了此进程现在打开的全部FD的状态,此数据长度为NR_OPEN,是单个进程能维护的FD数量上限。通俗的表示即是:通过A进程状态表中的filp[3],可访问到A进程打开的FD=3指向的文件状态。 - 文件表项(struct file): 上图中的file table entry结构,表示进程维护的文件状态,包含有进程打开此文件的方式(file status flags,如可读、可写等)、当前读写文件的偏移量(current file offset)以及实际文件数据在内存中的指针地址(v-node pointer)
- 实际的文件数据,由系统在打开此文件后加载到内存中,即v-node,各unix-like系统有不同的实现方式,此处略过。
Q:同一进程内,可以打开不同的FD,指定同一个v-node文件吗?
A:当然可以,只是两个FD可能拥有不同的文件状态(打开方式、偏移量等)。
Q:一边对文件append写入,另一边读取可以读到吗?
A:可以,即使是跨进程也能这么做。
Q:两个进程,能指向同一个文件表项吗?
A:可以,通过fork子进程或dup FD,均能做到共享一个文件表项。即共享文件的打开方式与偏移量。
2 文件操作
2.1 主要的几个C函数
int open(const char *path, int oflag, ... /* mode_t mode */ );
int creat(const char *path, mode_t mode);
int close(int fd);
off_t lseek(int fd, off_t offset, int whence);
ssize_t read(int fd, void *buf, size_t nbytes);
ssize_t write(int fd, const void *buf, size_t nbytes);
- open \ create函数打开\创建一个文件,并返回对应的FD,供后续执行close \ lseek \ read \ write等操作;
- lseek:可更改当前FD的文件状态的偏移量,whence可指定从哪个位置偏移(文件头、文件尾、当前位置);
- close:关闭文件,文件表项引用数减1,降为0时真正关闭文件;
- read \ write:对指定文件,读写指定字节数;
2.2 原子操作
考虑到多个进程可能并发的读写同一文件,因此对文件保证原子操作是有必要的,例如:
1. lseek(fd, 0, FILE_END);
2. write(fd, buf, len(buf));
两个进程同时执行以上代码时,A进程将指针移到文件尾部(步骤1),B进程已经完成了步骤1与2,A进程再执行步骤2时会将B写入的数据覆盖,不符合B的原意。
读写效率
观察如下代码:
int main(void)
{
int n;
char buf[BUFFSIZE];
while ((n = read(STDIN_FILENO, buf, BUFFSIZE)) > 0)
if (write(STDOUT_FILENO, buf, n) != n)
err_sys("write error");
if (n < 0)
err_sys("read error");
exit(0);
}
由于每次执行read \ write都会执行一次系统调用,也称为Unbuffered I\O函数,对于此类函数一次操作的字节数,会影响程序的运行效率。
那么此处的BUFFSIZE要如何指定,才能达到最佳效率呢?
- 图方便的话定为1024或4096,通常是最佳的。
- 使用stat函数查看此文件属性,使用stblksize字段作为一次读写的量,是系统推荐的最佳单次读写字节数。
四、权限
进程权限:real user\group ID, effective user\group ID, saved set-user\group-ID
文件权限:user RWX(read\write\exec), group RWX, other RWX
五、其它
[umask]
umask
umask -S
umask 027
[chmod]
[chown]
结语
来自《UNIX环境高级编程》
网友评论