1、Unix把文件描述符0与进程标准输入关联,把1与标准输出关联,把2与标准错误关联。
2、POSIX.1标准中STDIN_FILENO=0,STDOUT_FILENO=1,STDERR_FILENO=2。包含在头文件<unistd.h>中。
3、文件操作方式,包含在<fcntl.h>中。
O_RDONLY 只读打开
O_WRONLY 只写打开
O_RDWR 读、写打开
O_EXEC 只执行打开
O_SEARCH 只搜索打开(应用于目录)
O_APPEND 文件追加
O_CLOEXEC
O_CREAT 文件不存在则创建
O_DIRECTORY path必须是目录
O_EXCL 配合O_CREAT,文件存在报错
O_NOCTTY
O_NOFOLLOW 如果path引用的是一个符号连接,则出错
O_NONBLOCK
O_SYNC 使write等待物理I/O操作完成
O_TRUNC 将已存在文件长度截断为0
O_TTY_INIT
3、open函数
原型:int open(const char *path, int oflag, ...);
path为文件路径,oflag为上面各参数的“或”运算结果;
4、openat函数:
原型:int openat(int fd, const char *path, int oflag, ...);
5、open和openat函数返回的文件描述符一定最小的未用描述符数值。
6、create函数
原型:int create(const char *path, mode_t mode);
等效于open(path, O_WRONLY | O_CREAT | O_TRUNC, mode);
7、close函数
原型:int close(int fd);
关闭一个文件时,会释放该进程加在该文件上的所有记录锁。
8、lseek函数
原型:off_t lseek(int fd, off_t offset, int whence);//返回新的文件偏移量。
显式的为一个打开文件设置偏移量。whence表示从offset向后偏移量,可正可负。offset为SEEK_SET则从开始处算起,为SEEK_CUR则从当前位置算起,为SEEK_END则从文件尾算起。
9、read函数
原型:ssize_t read(int fd, void *buf, size_t nbytes);
返回:读到的字节数,如果已经在文件尾,则为0;
10、write函数
原型:ssize_t write(int fd; const void *buf, size_t nbytes);
返回:已写的字节数,出错返回-1;
11、I/O效率
用read和write复制一个文件,每次复制的buf大小影响着效率,经测试,1-4096效率在提高,之后不变。
12、文件共享
文件使用三种数据结构表示打开文件
(1)每个进程在进程表中都有一个记录项,记录相中包含一张打开文件的文件描述符列表,每个描述符占用一项。
a.文件描述符标志
b.指向一个文件表项的指针
(2)内核为所有打开文件维持一张文件表,每个文件表包含:
a.文件状态标志(读、写、添写,同步、非阻塞等)
b.当前文件偏移量
c.指向该文件v-node的指针
(3)每个打开文件有一个v-node,包含文件类型和对文件操作的各函数的指针,
大多数文件还包含了i-node,i-node包含了文件所有者、文件长度、文件在磁盘上实际位置指针等。
13、原子操作
函数pread和pwrite:
原型:ssize_t pread(int fd, void *buf, size_t nbytes, off_t offset);
返回读到的字节数,出错返回-1,相当于调用lseek后调用read,原子
ssize_t pwrite(int fd, const void *buf, size_t nbytes, off_t offset);
返回已写的字节数,出错返回-1,相当于调用lseek后调用write,原子
创建文件open函数:
在open函数中用O_CREAT和O_EXCL说明时,判断文件不存在即创建时是原子操作。
14、dup和dup2函数
原型:int dup(int fd);
int dup2(int fd, int fd2);
返回:成功则返回新的文件描述符,失败返回-1
(1)用于复制一个现有的文件描述符,dup函数返回的一定是当前可用的文件描述符中最小的数值。
(2)dup2函数可以用fd2指定新描述符的值。如果fd2已经打开,则先关闭。如果fd=fd2,则返回fd2,而不关闭它。
(3)这两个函数返回的新文件描述符与fd共享同一个文件表项。
(4)新文件描述符的执行时关闭标志总是由dup函数清除。
(5)复制一个文件描述符的另一个方法是fcntl函数。
dup2(fd, fd2)等同于close(fd2) + fcntl(fd, F_DUPFD, fd2);后者两步操作,不是原子
15、sync、fsync、fdatasync函数
原型:void sync(void);
作用:将所有修改过的块缓冲区排入写队列,然后返回,不等待实际写磁盘操作结束。
原型:int fsync(int fd);
返回:成功返回0,出错返回-1
作用:只对fd指定的文件起作用,并且等待写磁盘操作结束才返回;
适用于数据库这样的应用程序,确保修改过的块立即写到磁盘上。
原型:int fdatasync(int fd);
返回:成功返回0,出错返回-1
作用:类似于fsync,但是只影响文件的数据部分。而fsync还会同步更新文件的属性。
16、fcntl函数
原型:int fcntl(int fd, int cmd, ...);
返回:成功,依赖于cmd,出错返回-1
作用:改变已经打开文件的属性。
①复制一个已有的描述符 cmd=F_DUPFD或F_DUPFD_CLOEXEC
②获取/设置文件描述符标志 cmd=F_GETFD或F_SETFD
③获取/设置文件状态标志 cmd=F_GETFL或F_SETFL
④获取/设置一步I/O所有权 cmd=F_GETOWN或F_SETOWN
⑤获取/设置记录锁 cmd=F_GETLK、F_SETLK或F_SETLKW
F_DUPFD:复制文件描述符fd。新文件描述符作为函数值返回,是尚未打开的文件描述符中最小的。
新描述符与fd共享同一个文件表项,但有自己的一套文件描述符标志。
F_DUPFD_CLOEXEC:复制文件描述符,设置与新描述符关联的FD_CLOEXEC文件描述符标志的值,
返回新文件描述符。
F_GETFD:返回fd的文件描述符标志,当前只定义了一个文件描述符标志FD_CLOEXEC。
F_SETFD:设置fd的文件描述符标志,新标志按第三个参数设置,整型值。
F_GETFL:返回fd的文件状态标志。
O_RDONLY 只读打开
O_WRONLY 只写打开
O_RDWR 读、写打开
O_EXEC 只执行打开
O_SEARCH 只搜索打开(应用于目录)
O_APPEND 追加写
O_NONBLOCK 非阻塞模式
O_SYNC 等待写完成(数据和属性)
O_DSYNC 等待写完成(仅数据)
O_RSYNC 同步读和写
其中O_RDONLY、O_WRONLY、O_RDWR、O_EXEC、O_SEARCH并非各占一位,前三个取0/1/2,
因此需要先于屏蔽字O_ACCMODE取得访问位方式,然后与这5个值一一比较。
F_SETFL:将文件状态标志设置为第三个参数的值(整型),可以是O_APPEND、O_NONBLOCK、O_SYNC、
O_DSYNC、O_RSYNC、O_FSYNC、O_ASYNC。
F_GETOWN:获取当前接收SIGIO和SIGURG信号的进程ID或进程组ID。
F_SETOWN:设置接收SIGIO和SIGURG信号的进程ID或进程组ID。正的arg表示指定一个进程ID,
负的arg表示指定一个|arg|的进程组ID。
17、ioctl函数
ioctl一直是I/O操作的杂物箱。不能用本章的其他函数表示的I/O操作通常都能用ioctl表示。
终端I/O是使用ioctl最多的地方。
原型:#include<unistd.h>
#include<sys/ioctl.h>
int ioctl(int fd, int request, ...);