1. open和create函数在fcntl.h中,close、lseek、read、write函数在unistd.h中
open函数通过进程有效用户ID判断读文件的权限
可以调用access函数判断进程的实际用户ID对文件的权限
2. create函数以只读方式打开文件,create(pathname,mode)相当于open(pathname,O_RDONLY|O_CREATE|O_TRUNC,mode)
O_RDONLY|O_CREATE|O_TRUNC导致只能创建文件,不能写文件,所以还是直接调用open比较方便
3. 有些类型的文件不能设置偏移量,如管道、FIFO、网络套接字,但是仍然可以对这类文件调用lseek,不过返回-1,errno被设置为ESPIPE
标准输入不能被设置偏移量,重定向到某些类型的文件后可以设置偏移量
int main() { if(lseek(STDIN_FILENO,0,SEEK_CUR)==-1) perror("lseek error"); else printf("lseek success\n"); }
直接运行:
./a
lseek error: Illegal seek
重定向到一般文件:
./a < a.c
lseek success
通过管道:
cat < a.c | ./a
lseek error: Illegal seek
4 od -c将以字符方式打印文件的实际内容
5 read和write函数的缓冲区定义为void*,一般会用char*类型的缓冲区,如果是其他类型的呢?
ISO C定义为void*,POSIX定义为char*
int buf[10]; int n = read(STDIN_FILENO,buf,10); write(STDOUT_FILENO,buf,n);
仍然可以正常运行
read读到末端继续读返回0
6 内核用于表示打开的文件的数据结构
1)每个进程在进程表中的记录项包含一张打开文件描述符表,记录:
a)文件描述符
b)文件描述符标志(close_on_exec,即exec时文件描述符是否关闭,同一进程的两个指向同一文件的文件描述符可能具有不同的文件描述符标志,dup函数不会复制文件描述符标志)
c)指向文件表项的指针
2)文件表项(对同一文件,公共祖先进程之间共享,非公共祖先进程之间单独维护)包含:
a)文件打开方式
b)文件偏移量
c)指向v节点表项的指针
3)v节点结构:
v节点信息:文件类型和对此文件进行各种操作的函数的指针
i节点信息:文件所有者、文件长度、文件所在设备
三种数据结构形成了一种层级关系
打开文件描述符表记录的信息是公共祖先进程之间都可以不同的信息,所以每个进程单独维护
文件表项记录的是不同公共祖先进程之间可以不同的信息,所以公共祖先进程共享一个文件表项
v节点结构记录的是文件不针对进程而不同的信息,每个文件只有一个v节点结构,所有进程共用
dup函数为进程复制一个现存的文件描述符,进程将会有两个文件描述符指向同一个文件表项,但是进程的打开文件描述符表项中记录了文件描述符标志,这个标志不会被复制,即dup函数会清除文件描述符的close_on_exec位
打开/dev/fd/n相当于复制文件描述符n
7 设置偏移量与读写的原子操作
从6可以看出,不同进程之间可以设置不同的文件偏移量(记录在文件表中,不同进程单独维护,父子进程共享)
pread和pwrite在read和write的基础上添加一个参数,用于设置从某个偏移量开始读写:
ssize_t pread(int fd,const void *buf,size_t bnytes,off_t offset)
ssize_t pwrite(int fd,void *buf,size_t bnytes,off_t offset)
8 fcntl函数的cmd参数
F_DUPFD:复制文件描述符
F_GETFD/F_SETFD:获取/设置文件描述符标志(close_on_exec)
F_GETFL/F_SETFL:获取/设置文件状态标志(文件打开方式)
F_GETLK/F_SETLK/F_SETLKW:获取/设置记录锁
F_GETOWN/F_SETOWN:获取/设置异步I/O所有权,即获取/设置 接收SIGIO和SIGURG信号的进程或进程组ID