3.15 fcntl函数(3)-利用F_GETFL/SET_FL获取或者设置文件状态标志

fcntl函数可以改变已打开文件的性质。函数原型如下:

#include <fcntl.h>
int fcntl(int filedes, int cmd, ...);

当第二个参数cmd=F_GETFL时,它的作用是取得文件描述符filedes的文件状态标志。

当第二个参数cmd=F_SETFL时,它的作用是设置文件描述符filedes的文件状态标志,这时第三个参数为新的状态标志。


返回值:若成功则返回文件状态标志,若出错则返回-1。

函数返回一个整数,该整数低2位表示读写状态,其他位每个位代表一个状态。

fcntl函数可获取或者设置的状态标志列表如下:

fcntl函数可获取或者设置的状态标志表
文件状态标志标志值(八进制)可否通过F_GETFL获取可否通过F_SETFL设置说明
O_RDONLY00只读打开
O_WRONLY01只写打开
O_RDWR02为读、写打开
O_APPEND02000每次读写在尾部追加
O_NONBLOCK04000非阻塞模式
O_SYNC04010000等待写完成(数据和属性)
O_DSYNC010000等待写完成(仅数据)
O_RSYNC04010000同步读、写
O_FSYNC04010000等待完成
O_ASYNC020000异步I/O
     

从上表可以看出:

1、文件读写状态并非一个位代表一个状态,而是一个互斥值。所以无法通过返回值与状态字的与运算来判断读写状态。要从返回状态中提取读写状态值,首先要用屏蔽字(O_ACCMODE)取得读写状态位,然后再分别与三个读写状态字进行比较。

2、文件读写状态不能通过fcntl的F_SETFL来设置。

下面实例中函数set_fl用来设置文件状态标志,函数clr_fl用来清除文件状态标志。两个函数中的第二个参数flags可以是上表中个状态字或其组合,但对于文件读写状态(O_RDONLY、O_WRONLY和O_RDWR)无效,也不适用。

实例用O_APPEND状态字来测试两个函数(set_flclr_fl)的效果。

实例 x.3.14.3.c

#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

#define BUFFSIZE 256

void set_fl(int fd, int flags);
void clr_fl(int fd, int flags);

int main()
{
    char       filepath[] = "/tmp/myfile"; /*待操作文件路径*/
    int        f_id;                       /*文件描述符*/
    
    ssize_t      nrdwr;                      /*实际读写字节书*/
    size_t       nbytes;                     /*要读写的字节书*/
    off_t        offset;                     /*文件指针偏移量*/
    char        wbuf[BUFFSIZE] = "0123456789abcdefghij"; /*待写入数据*/

/*打开文件,获取文件描述符*/
    f_id = open(filepath, O_RDWR | O_CREAT);
    if (f_id == -1) {
	printf("open error for %s\n", filepath);
	exit(1);
    }

/*把文件指针移动到文件开始处*/
    offset = lseek(f_id, 0, SEEK_SET);
    if (offset == -1) {
        printf("lseek error\n");
        exit(1);
    }

/*写入10字节数据[0-9]*/
    nbytes = 10;
    nrdwr = write(f_id, wbuf, nbytes);
    if (nrdwr == -1) {
        printf("write error\n", f_id);
        exit(1);
    }

/*设置为每次写时追加到尾部*/
/*    set_fl(f_id, O_APPEND);*/

/*清除追加到尾部状态标志*/
/*    clr_fl(f_id, O_APPEND);*/

/*再把文件指针移回文件开始处*/
    offset = lseek(f_id, 0, SEEK_SET);
    if (offset == -1) {
        printf("lseek error\n");
        exit(1);
    }

/*再写入10字节数据[a-j]*/
    nbytes = 10;
    nrdwr = write(f_id, (wbuf + 10), nbytes);
    if (nrdwr == -1) {
        printf("write error\n", f_id);
        exit(1);
    }

/*关闭文件描述符*/
    close(f_id);

    exit(0);
}

/*设置文件状态标志*/
void set_fl(int fd, int flags)
{
    int val;

/*取原状态(包含着其他方面的状态)*/
    if ((val = fcntl(fd, F_GETFL, 0)) < 0) {
        printf("fcntl error for F_GETFL");
        exit(1); 
    }
 
/*置位指定状态位flags*/   
    val |= flags;

/*设置新状态*/
    if (fcntl(fd, F_SETFL, val) < 0) {
        printf("fcntl error for F_SETFL");
        exit(1);
    }
}

/*清除文件状态标志*/
void clr_fl(int fd, int flags)
{
    int val;

/*取原状态(包含着其他方面的状态)*/
    if ((val = fcntl(fd, F_GETFL, 0)) < 0) {
        printf("fcntl error for F_GETFL");
        exit(1); 
    }

 /*清除指定状态位flags*/     
    val &= ~flags;

/*设置新状态*/
    if (fcntl(fd, F_SETFL, val) < 0) {
        printf("fcntl error for F_SETFL");
        exit(1);
    }
}

编译与执行:

第一步:上诉代码直接编译

[root@localhost unixc]# rm -f /tmp/myfile
[root@localhost unixc]# cc x.3.14.3.c
[root@localhost unixc]# ./a.out
[root@localhost unixc]# cat /tmp/myfile
abcdefghij[root@localhost unixc]#

结果分析:第二次写入的内容把第一次写入的内容给覆盖掉了。


第二步:将上面代码中的44行“/*    set_fl(f_id, O_APPEND);*/”注释符去掉激活该行代码,然后继续编译测试

[root@localhost unixc]# rm -f /tmp/myfile
[root@localhost unixc]# cc x.3.14.3.c
[root@localhost unixc]# ./a.out
[root@localhost unixc]# cat /tmp/myfile
0123456789abcdefghij[root@localhost unixc]# 

分析:O_APPEND状态位被设置,第二次写入的东西[abcdefghij]不覆盖前面的[0123456789]。


第三步:将上面代码中的44行“/*    set_fl(f_id, O_APPEND);*/”47行“/*    clr_fl(f_id, O_APPEND);*/”两行代码中的注释符去掉激活代码,然后继续编译测试

[root@localhost unixc]# rm -f /tmp/myfile
[root@localhost unixc]# cc x.3.14.3.c
[root@localhost unixc]# ./a.out
[root@localhost unixc]# cat /tmp/myfile
abcdefghij[root@localhost unixc]#

结果分析:设置状态后紧接着又清除了,等价于第一步。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值