尊重作者劳动成果,转载请注明出处,谢谢!
1.概述
所有执行 I/O 操作的系统调用都以文件描述符(一个非负整数)来指代打开的文件,如普通文件、套接字、目录文件、符号链接等。
标准文件描述符:
- 0:标准输入,POSIX 名称:STDIN_FILENO,stdio 流:stdin
- 1:标准输出,POSIX 名称:STDOUT_FILENO,stdio 流:stdout
- 2:标准错误,POSIX 名称:STDERR_FILENO,stdio 流:stderr
执行文件 I/O 操作的主要系统调用:
#include <fcntl.h> int open (const char *path, int oflag, ... /* mode_t mode */); //打开或创建一个文件,成功返回文件描述符,失败返回 -1 int fcntl (int fd, int cmd, ... /* int arg */); //改变已打开文件的属性 #include <unistd.h> int close (int fd); //关闭一个打开文件,成功返回,失败返回 -1 ssize_t read (int fd, void *buf, size_t nbytes); //从打开文件中读数据,成功返回读取的字节数,若已到达文件尾则返回 0,失败返回 -1 ssize_t write (int fd, const void *buf, size_t nbytes); //向打开文件写数据,成功返回写入的字节数,失败返回 -1 off_t lseek (int fd, off_t offset, int whence); //设置文件偏移量,成功返回新的文件偏移量,失败返回 -1
2.使用 open 函数打开或创建文件
用下列一个或多个常量进行“或”运算构成 open() 函数中的 oflag 参数,这些常量在头文件 <fcntl.h> 中定义:
①文件访问模式
- O_RDONLY(0):以只读方式打开文件
- O_WRONLY(1):以只写方式打开文件
- O_RDWR(2):以读写方式打开文件
如下代码以只读的方式打开 path 指定的文件,返回的文件描述符赋值给变量 fd:
int fd; fd = open(path, O_RDONLY);
②文件创建标志
- O_CLOEXEC:把 FD_CLOEXEC 常量设置为文件描述符标志,当该标志打开时,子进程从父进程继承的该文件描述符将被关闭
- O_CREAT:若文件不存在,则创建它,使用该选项时,需要同时指定 mode 参数(文件访问权限)
- O_EXCL:如果同时指定了 O_CREAT,而文件已经存在,则出错(errno 为 EEXIST)
- O_TRUNC:截断已有文件,使其长度为零
- O_NOCTTY:不要让 path (所指向的终端设备)成为控制终端
- O_DIRECTORY:如果 path 不是目录,则出错
③文件状态标志
- O_APPEND:总在文件尾部追加数据
- O_ASYNC:当 I/O 操作可行时,产生信号通知进程
- O_SYNC:以同步方式写入文件,使每次 write 等待物理 I/O 操作完成,包括由该 write 操作引起的文件属性更新所需的 I/O
- O_NONBLOCK:若文件是一个 FIFO、一个块特殊文件或一个字符特殊文件,则此选项的本次打开操作和后序的 I/O 操作设置非阻塞方式
3.使用 lseek 函数改变文件偏移量
对于每个打开的文件,系统内核会记录其文件偏移量。当文件打开时,会将文件偏移量设置为指向文件的开始,以后每次 read 或 write 时将自动对其进行调整,以指向已读或已写数据后的下一字节。
offset 参数指定了一个以字节为单位的数值,whence 参数则表明应参照哪个位置来解释 offset 参数,whence 参数取值如下:
- SEEK_SET:从文件头部起始点开始的 offset 个字节
- SEEK_CUR:相对于当前文件偏移量,将文件偏移量调整 offset 个字节
- SEEK_END:将文件偏移量设置为起始于文件尾部的 offset 个字节
4.使用 fctnl 函数改变打开文件的属性
fcntl 函数有以下 5 种功能:
- 复制一个已有的描述符(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)