fcntl函数 -- 功能强大的文件状态操作函数

2014-07-16 22:24:43   最后更新: 2014-07-16 22:24:43   访问数量:958




UNIX下的fcntl函数可以改变已打开的文件性质

int fcntl(int fd , int cmd, ... );

 

 

  1. 复制一个现有的文件描述符     cmd=F_DUPFD
  2. 获得/设置文件描述符标记      cmd=F_GETFD 或 F_SETFD
  3. 获得/设置文件状态标志        cmd=F_GETFL 或 F_SETFL
  4. 获得/设置异步IO所有权        cmd=F_GETOWN 或 F_SETOWN
  5. 获得/设置记录锁              cmd=F_GETLK、F_SETLK 或 F_SETLKW

 

  • F_DUPFD -- 复制文件描述符
  • 前面有介绍过另外两个UNIX文件描述符复制函数:DUP 和 DUP2

    指定该参数后,fcntl函数用于复制文件描述符,新的文件描述符作为函数值返回,第三个参数是新的文件描述符,如第三个参数的文件描述符已经被打开,那么就会使用大于等于第三个参数的数值中最小的一个

    新的文件描述符与fd共享同一个文件表项,但新的文件描述符有他自己的一套文件描述符标志,其 FD_CLOEXEC 文件描述符被清除(这表示该描述符在通过一个 exec 后依然保持有效)

     

  • F_GETFD -- 获取文件描述符标志
  • 函数返回对应于fd的文件描述符标志,当前只定义了一个文件描述符标志 FD_CLOSEXEC

     

  • F_SETFD -- 设置文件描述符标志
  • 将文件描述符标志设置为第三个参数

     

  • F_GETFL -- 获取文件状态标志
  • 返回文件状态标志

     

  • F_SETFL -- 设置文件状态标志
  • 将文件状态标志设置为第三个参数

 

文件状态标志:

O_RDONLY           只读打开 (不可由函数更改)

O_WRONLY           只写打开 (不可由函数更改)

O_RDWR             读写打开 (不可由函数更改)

O_APPEND           每次写时追加到文末

O_NONBLOCK         非阻塞模式

O_SYNC             等待写完成 (数据和属性)

O_DSYNC            等待写完成 (仅数据)

O_RSYNC            同步读写

O_FSYNC            等待写完成 (仅用于FreeBSD 和 MAC OS X)

O_ASYNC            异步IO (仅用于FreeBSD 和 MAC OS X)

 

fcntl函数的返回值与第二参数即函数的功能有关,但是一旦调用出错,所有命令都返回-1

 

需要注意的是,F_GETFD 和 F_SETFD 操作的都是文件描述符表项,而 F_GETFL 和 F_SETFL 操作的都是文件表项

 

#include "../apue.2e/include/apue.h" #include <fcntl.h> int main (int argc, char *argv[]) { int val; if (argc!=2) err_quit ("usage: a.out <descriptor>"); if ((val = fcntl (atoi(argv[1]), F_GETFL, 0))<0) err_sys ("fcntl error for fd %s", argv[1]); switch (val & O_ACCMODE) { case O_RDONLY: printf ("read only"); break; case O_WRONLY: printf ("write only"); break; case O_RDWR: printf ("read write"); break; default: err_dump ("unknown access mode"); } if (val & O_APPEND) printf (", append"); if (val & O_NONBLOCK) printf (", nonblocking"); putchar ('\n'); return 0; }

 

 

注意的一点是由于三个访问方式标志O_RDONLY、O_WRONLY、O_RDWR并不是各占一位,因此首先必须用屏蔽字O_ACCMODE取得访问模式位,然后再做比较 (程序第12行)

 

对于修改文件描述符标志值时必须谨慎,先要取得现有标志位值,然后根据需要修改他,最后设置新的标志值,不能只是执行F_SETFD或F_SETFL,这样会关闭一千设置的标志位。

 

#include <fcntl.h> #include "../apue.2e/include/apue.h" #define BUFFSIZE 4096 void set_fl (int fd, int flags) { int val; if ((val = fcntl(fd, F_GETFL, 0)) < 0) err_sys ("fcntl F_GETFL error"); val |= flags; if (fcntl (fd, F_SETFL, val) < 0) err_sys ("fcntl F_SETFL error"); } int main () { int n; char buf [BUFFSIZE]; set_fl (STDOUT_FILENO, O_SYNC); while ((n = read(STDIN_FILENO, buf, BUFFSIZE)) > 0) if (write(STDOUT_FILENO, buf, n)!=n) err_sys ("write error"); if (n<0) err_sys ("read error"); exit(0); }

 

 

注意在 21 行,调用 set_fl (STDOUT_FILENO, O_SYNC); 后,每次读写都会等待写操作完成,直到数据已经写到磁盘上再返回,这样会使得程序的运行时间增加。但可以保证写数据的正确性

 

与另两个文件更新函数 fsync 和 fdatasync 相比,O_SYNC 标志在我们每次写至文件时都会更新文件内容,而拿两个函数则是在我们需要时更新文件内容

 

对于 fcntl 函数,我们只需提供文件描述符参数即可实现文件状态的更改,而无需指定文件名

 






读书笔记      技术帖      linux      unix      c++      cpp      c语言      龙潭书斋      apue      fcntl     


京ICP备15018585号