文件描述符是一个非负整数,当打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符,对于内核而言,所有打开的文件都是通过文件描述符引用。
原型:
int open (const char * path,int oflag,......);
int openat (int fd, const char * path,int oflag , ......);//两函数的返回值若成功返回文件描述符,若出错返回-1.
参数path是要打开或创建的名字
oflag参数表示如何打开文件:
O_RDONLY //只读打开
O_WRONLY //只写打开
O_RDWR //读、写打开
O_APPEND //每次读写时都要追加到文件的底端
O_CREAT //若文件不存在则创建它,使用时open函数需要说明第三参数为mode(openat()函数需要说明第四参数为mode)
参数fd把两函数区分开来:
1.如果path指定的是绝对路径时,fd将被自动忽略,两函数无区别;
2..如果path指定的是相对路径时,fd参数指出了相对路径名在文件系统中的开始地址。
3.如果path指定的是相对路径时,fd参数具有特殊值AT_FDCWD 路径名在当前工作目录中获取,此时两者功能相似。
openat()函数存在意义:
1.可以使用相对路劲名打开目录中的文件,不仅仅只是打开当前工作目录。
2.避免TOCTTOU错误。
TOCTTOU错误: 如果有两个基于文件的函数调用,其中第二个调用依赖于第一个调用的结果,那么程序是脆弱的。因为两个调用并不是原子操作,在两个函数调用之间文件可能改变了,这样也就造成了第一个调用的结果就不再有效,是的程序最终的结果是错误的
creat 函数
int creat(const char * path , mode_t mode);
等价于
open(path,O_WRONLY | O_CREAT | O_TRUNC , mode )
每一个打开文件都有一个与其相关联的“当前文件偏移量,当一个文件打开时除非指定O_APPEND选项,否则偏移量被设置为0;
off_t lseek(int fd, off_t offset, int whence);//若成功返回新的文件偏移量;若出错返回-1;
whence 有三种设置:
whence | 表示的内容 |
---|---|
SEEK_SET | 偏移量为从文件开头处的offset个字节 |
SEEK_CUR | 偏移量为从当前偏移位置加offset个字节(offset可正可负) |
SEEK_END | 偏移量为从文件的结尾加offset个字节(offset可正可负) |
有的系统也把上述三个用0、1、2来表示。
文件空洞:文件的偏移量大于当前文件长度时,当下一次改文件执行写操作时,中间有空白。
文件中的空洞并不要求在磁盘上占用存储区。
od 命令//使用该命令观察文件的实际内容(文件空洞显示\0)
od -c 文件名//-c 表示以字符方式打印文件内容
注意:和cat命令的区别
int read (int fd, char * buf, unsigned nbytes);//从文件中读到buf中
返回读到的字节数,若读到结尾返回0,出错返回-1;
size_t write (int fd, char * buf, unsigned nbytes);//从文件中读到buf中
返回读到的字节数,出错返回-1;
进程打开文件:
(1)每一个进程在进程表中有一个记录项,记录项中包含一张打开文件描述符的表,每一个文件描述符包含:a.文件描述符的标志 b.指向一个文件表项的指针;
(2)每一个文件表项包含:
a.文件的状态标志;
b.当前文件偏移量;
c. v节点表项的指针;
(3)v节点包含:文件类型、对文件进行操作的各种指针,i节点;
i节点包含:文件的所有者、文件的长度、文件数据所在磁盘上的位置指针。
原子操作指的是由多步组成的一个操作。
原子操作的两个函数:
size_t pread(int fd, void *buf , size_t nbytes, off_t offset);
//相当于先调用lseek后调用read,返回读到的字节数,若已到文件结尾返回0,出错返回-1;
size_t pwrite(int fd, void *buf , size_t nbytes, off_t offset);
//相当于先调用lseek后调用write,返回已写的字节数,出错返回-1;
//复制一个现有文件描述符
//函数返回值若成功,返回新的文件描述符,出错返回-1;
int dup (int fd);
int dup2 (int fd, int fd2);//返回的文件描述符可以通过第二个参数”可用的文件描述符“指定。如果“可用的文件描述符“是打开状态,则会被关闭;如果”现存的文件描述符“和”可用的文件描述符“一样,则不会关闭
图3 内核dup后内核的数据结构
更多关于dup和dup2函数的信息:
http://www.01happy.com/c-dup-dup2/
int fcntl(int fd, int cmd, …);
函数的功能:
1、复制一个已有的描述符(cmd =F_DUPFD或 F_DUPFD_CLOEXEC);
2、 获取/设置文件描述符标志(cmd=F_GETFD或F_SETFD);
3、 获取/设置文件状态标志(cmd=F_GETFL或F_SETFL);
4、 获取/设置异步I/O所有权(cmd=F_GETOWN或F_SETOWN);
5、 获取/设置记录锁(cmd=F_GETLK或F_SETLK、F_SETLWK);