文件描述符
所有打开的文件都通过文件描述符引用,它是一个非负整数。
0表示标准输入STDIN_FILENO,1表示标准输出STDOUT_FILENO,2表示标准错误输出STDERR_FILENO。
文件描述符的变化范围是0-OPEN_MAX。
open函数
#include <fcntl.h>
int open(const char *pathname, int aflag, ... /* mode_t mode */);
pathname:打开或创建的文件名
aflag:函数选项
必选项:
O_RDONLY 只读打开
O_WRONLY 只写打开
O_RDWR 读写打开
可选项:
O_APPEND 写时追加到尾端
O_CREAT 文件不存在则创建并用到第三参数
O_EXCL 测试文件是否存在,若不存在则创建
O_TRUNC 文件存在并只写或读写打开,文件截短为0
O_NOCTTY pathname若是终端设备,则不讲该设备分配作为此进程的控制终端
O_NONBLOCK非阻塞模式
O_DSYNC 每次write等待物理IO操作完成,若写操作不影响读取刚写入的数据,则不等待文件属性更新
O_RSYNC read操作等待直到任何对文件同一部分的写操作完成
O_SYNC 每次write等待物理IO操作完成,包括由write引起的文件属性更新所需的IO
open函数返回最小的未分配描述符,出错返回-1。
creat函数
#include <fcntl.h>
int creat(const char *pathname, mode_t mode);
close函数
#include <unistd.h>
int close(int filedes);
lseek函数
#include <unistd.h>
off_t lseek(int filedes, off_t offset, int whence);
whence:若为SEEK_SET,则偏移量距文件开始offset字节;若为SEEK_CUR,则偏移量为当前值加offset字节;若为SEEK_END,则偏移量为文件长度加offset字节。
offset:打开文件时除非指定O_APPEND,否则偏移量设为0。
lseek函数返回新的文件偏移量,出错返回-1。偏移量可以是负值,判断错误要和-1比较。
read函数
#include <unistd.h>
ssize_t read(int filedes, void *buf, size_t nbytes);
read函数返回读到的字节数,若已到达文件结尾,则返回0,出错返回-1。
write函数
#include <unistd.h>
ssize_t write(int filedes, const void *buf, size_t nbytes);
write函数返回写入的字节数,出错返回-1。
原子操作
多个进程读同一文件都能正确工作,每个进程都有自己的文件表项和偏移量,但多个进程写同一文件时可能产生意料不到的结果。避免这个问题需要使用原子操作。
#include <unistd.h>
ssize_t pread(int filedes, void *buf, size_t nbytes, off_t offset);
ssize_t pwrite(int filedes, const void *buf, size_t nbytes, off_t offset);
pread相当于lseek和read,pwrite相当于lseek和write,但是之间无法中断。
int dup(int filedes);
复制一个文件描述符。
int dup2(int filedes, int filedes2);
等效于
close(filedes2);
fcntl(filedes, FDUPFD, filedes2);
区别是它是一个原子操作。
一致性
UNIX一般采用延迟写技术减少磁盘访问,降低了文件更新速度,可使用以下函数更新。
#include <unistd.h>
int fsync(int filedes);
int fdatasync(int filedes);
void sync(void);
sync将修改过的缓冲区排入写队列返回,不等待写结束;fsync只对单一文件起作用,并等待写结束后返回,fdatasync类似于fsync,但是只影响数据部分,不影响文件属性。
fcntl函数
fcntl函数改变打开文件的性质。
#include <fcntl.h>
int fcntl(int filedes, int cmd, ... /* int arg */);
cmd:
F_DUPFD 复制现有描述符
F_GETFD或F_SETFD 获得/设置描述符
F_GETFL或F_SETFL 获得/设置文件标志,先使用掩码O_ACCMODE获得访问模式位
F_GETOWN或F_SETOWN 获得/设置异步IO所有权
F_GETLK、F_SETLK或F_SETLKW 获得/设置记录锁
ioctl函数
#include <unistd.h>
#include <sys/ioctl.h>
#include <stropts.h>
int ioctl(int filedes, int request, ...);
通常需要另外的设备专用头文件,如终端IO的ioctl命令需要使用<termios.h>。