zoukankan      html  css  js  c++  java
  • 文件I/O之fcntl函数

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

    #include <fcntl.h>
    int fcntl( int filedes, int cmd, ... /* int arg */ );
    返回值:若成功则依赖于cmd,若出错则返回-1

    在本节的各实例中,第三个参数总是一个整数,与上面所示函数原型中的注释部分相对应。但是在说明记录锁时,第三个参数则是指向一个结构的指针。

    fcntl函数有5种功能:

    (1)复制一个现有的描述符(cmd = F_DUPFD )。

    (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_SETLKW)。

    我们先说明这10种cmd值得前7种(后3种,在谈记录锁时说明)。我们将涉及与进程表项中各文件描述符相关联的文件描述符标志,以及每个文件表项中的文件状态标志。

    F_DUPFD         复制文件描述符filedes。新文件描述符作为函数值返回。它是尚未打开的各描述符中大于或等于第三个参数值(取为整型值)中各值的最小值。新描述符与filedes共享同一文件表项。但是,新描述符有它自己的一套文件描述符标志,其FD_CLOEXEC文件描述符标志被清除(这表示该描述符在通过一个exec时仍保持有效)。

    F_GETFD         对应于filedes的文件描述符标志作为函数值返回。当前只定义了一个文件描述符标志FD_CLOEXEC。

    F_SETFD         对于filedes设置文件描述符标志。新标志值按第三个参数(取为整型值)设置。

    注:应当了解很多现有的涉及文件描述符标志的程序并不使用常量FD_CLOEXEC,而是将此标志设置为0(系统默认,在exec时不关闭)或1(在exec时关闭)。

    F_GETFL         对应于filedes的文件状态标志作为函数值返回。文件状态标志如下表3-3:(表3-3中的各个标志,除了三个访问方式标志(O_RDONLY、O_WRONLY以及O_RDWR)不各占一位,其他标志分别占文件状态标志的一个bit位)

    index

    不幸的是,三个访问方式标志(O_RDONLY、O_WRONLY以及O_RDWR)并不各占1位(由于历史原因,这三种标志的值分别是0、1和2。这三个访问方式标志用文件状态标志的后两位表示,00:O_RDONLY,01:O_WRONLY,10:O_RDWR。这三种值互斥——一个文件只能有这三种值之一)。因此首先必须用屏蔽字O_ACCMODE(0x0003)取得访问模式位(文件状态标志的后两位),然后将结果与这三种值的任一种做比较。

    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。

    fcntl的返回值与命令有关。如果出错,所有命令都返回-1,如果成功则返回某个其他值。下列四个命令有特定的返回值:F_DUPFD、F_GETFD、F_GETFL以及F_GETOWN。第一个返回新的文件描述符,接下来两个返回相应标志,最后一个返回一个正当进程ID或负的进程组ID。

    程序清单3-4 对于指定的描述符打印文件标志

    [root@localhost apue]# cat prog3-4.c
    #include "apue.h"
    #include <fcntl.h>
    
    int 
    main(int argc, char *argv[])
    {
            int val;
    
            if(argc != 2)
                    err_quit("usage: prog3-4 <descriptor#>");
    
            if((val = fcntl(atoi(argv[1]), F_GETFL, 0)) < 0)
                    err_sys("fcntl error for fd %d", atoi(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");
    #if defined(O_SYNC)
            if(val & O_SYNC)
                    printf(", synchronous writes");
    #endif
    #if !defined(_POSIX_C_SOURCE) && defined(O_FSYNC)
            if(val & O_FSYNC)
                    printf(", synchronous writes");
    #endif
            putchar('
    ');
            exit(0);
    }

    注意,我们使用了功能测试宏_POSIX_C_SOURCE,并且条件编译了POSIX.1中没有定义的文件访问标志。

    在修改文件描述符标志或文件状态标志时必须谨慎,先要取得现有的标志值,然后根据需要修改它,最后设置新标志值。不能只是执行F_SETFD或F_SETFL命令,这样会关闭以前设置的标志位。

    程序清单3-5 对一个文件描述符打开一个或多个文件状态标志

    [root@localhost apue]# cat prog3-5.c
    #include "apue.h"
    #include <fcntl.h>
    
    void 
    set_fl(int fd, int flags) /* flags are file status flags to turn to */
    {
            int val;
    
            if((val = fcntl(fd, F_GETFL, 0)) < 0)
                    err_sys("fcntl F_GETFL error");
    
            val |= flags;   /* turn on flags */
    
            if(fcntl(fd, F_SETFL, val) < 0)
                    err_sys("fcntl F_SETFL error");
    }

    如果将中间的一条语句改为:

    val &= ~flags;    /* turn flags off */

    就构成另一个函数,我们称其为clr_fl。

    比较fsync和fdatasync与O_SYNC标志,fsync和fdatasync在我们需要时更新文件内容,O_SYNC标志则在我们每次写至文件时更新文件内容。

    fcntl的必要性:我们的程序在一个描述符(标准输出)上进行操作,但是根本不知道由shell打开的相应的文件名。因为这是shell打开的,于是不能在打开时,按我们的要求设置O_SYNC标志。fcntl则允许仅知道打开文件描述符时可以修改其性质。

    本篇博文内容摘自《UNIX环境高级编程》(第二版),仅作个人学习记录所用。关于本书可参考:http://www.apuebook.com/

  • 相关阅读:
    配置使用EF常见的一些问题及解决方案
    js定时器的使用(实例讲解)
    MySQL Workbench 修改快捷键
    Linux CentOS 启动 网卡
    Linux CentOS 安装 VMware Tools
    Linux 群晖 DokuWiki 安装
    Linux CentOS 系统安装 和 相关配置
    接口 Postman 提交json对象到后台 Request Payload
    PHP 文件上传
    电商系统 项目管理 GIT的使用
  • 原文地址:https://www.cnblogs.com/nufangrensheng/p/3500350.html
Copyright © 2011-2022 走看看