现在的位置: 首页 > 综合 > 正文

linux 文件状态标识和IO操作方式

2018年01月22日 ⁄ 综合 ⁄ 共 3673字 ⁄ 字号 评论关闭

转自:http://book.2cto.com/201212/11767.html 来自《UNIX/Linux程序设计教程

文件状态标签指明文件的打开属性,它们由open()的flags参数指明(见表3-1)。与描述字标签不同,文件状态标签由与同一次打开文件相连的所有重复文件描述字所共享(参见图3-3)。文件状态标签中的标志可分为三类:访问方式、打开时标志和I/O操作方式。

1. 访问方式

访问方式指明允许文件描述字用于读、写或两者兼之,包括O_RDONLY、O_WRONLY和O_RDWR。这些访问方式在文件被打开时选定,之后便不能再改变。

为了确定文件访问方式,必须从fcntl()取回的文件状态标签中抽取访问方式。因为读和写访问方式不一定是独立的标志位,因此抽取文件访问方式的可移植方法是用宏常数O_ACCMODE位串与文件状态标签值作按位与操作(C中的'&'运算),由此生成表示文件访问方式的值,即O_RDONLY、O_WRONLY或O_RDWR(参见程序3-5)。

2. 打开时标志

打开时标志指明打开文件时影响open()行为的一些选项。这些选项一旦文件打开就不保留,但有一个例外是O_NONBLOCK,因为O_NONBLOCK同时也是一个I/O操作方式,故此标志被保留(3.7节)。

O_CREAT:若设置,当该文件不存在时创建此文件。

O_EXCL:若O_CREAT和O_EXCL同时设置,则当指定的文件已经存在时,open()失败。这保证不会破坏已存在的文件。

O_NONBLOCK:防止open()为打开文件而阻塞很长时间。这通常仅对诸如串行端口的设备文件才有意义。O_NONBLOCK标志同时也作为I/O操作方式标志,这意味着在open()中指明O_NONBLOCK就同时设置了非阻塞I/O方式(3.7节)。为了非阻塞地打开一个文件且不影响正常的阻塞I/O,必须先设置O_NONBLOCK来调用open(),然后调用fcntl()关闭此位。

O_NOCTTY:若命名的文件是终端设备,不让它成为该进程的控制终端(6.9节)。

O_TRUNC:截断文件为零长度,这一选项只对普通文件(4.2.1节)有用,对诸如目录或FIFO之类的特殊文件(4.2.5节)无用。由open()来做截断而不直接调用ftruncate()函数并没有什么太好的理由,只是因为O_TRUNC标志在ftruncate()引入之前就已存在于UNIX中,保留它只是为了向下兼容。

3. I/O操作方式

I/O操作方式影响使用文件描述字进行输入输出操作的工作方式。这些标志由open()设置,之后可以用fcntl()获取和改变。

O_APPEND:文件的附加方式位。若此位设置,所有write()操作写数据至文件尾而不管文件位置在何处。这是附加数据至文件尾唯一可靠的方法。用附加方式可以保证无论是否有其他进程正在写同一个文件,write()操作总是将数据写在当前文件尾。相反,在未设置此位的情况下,如果通过简单地移动文件位置到文件尾,然后再写数据,则在设置文件位置之后开始写之前,可能有其他进程扩展此文件(对应于两个不同的进程打开同一个文件的情形,它们共享同一个vnode,但各自有自己的系统打开文件表,因而有自己的文件位置,参见图3-2),从而导致所写的数据出现在实际文件尾之前的某个地方。

O_NONBLOCK:此标志同时也作为I/O操作方式标志。如果这一位设置,对文件的read()请求,当无立即可用的输入时能以EAGAIN错误状态立即返回,而不是阻塞。类似地,write()请求也能在输出不能写出时以EAGAIN错误状态立即返回。

O_ASYNC:此标志用于信号驱动的I/O(10.2节)。如果这一位设置,当文件描述字中有输入数据时会生成SIGIO信号。

O_SYNC:如果这一位设置,文件按同步I/O方式打开,并将导致任何写该文件的操作都阻塞调用进程直至数据(包括内核I/O缓冲区中的数据)以及与此次写有关的文件属性(4.1.1节)已全部写至物理存储介质(3.9节)。

O_DSYNC:如果这一位设置,文件按同步I/O方式打开,并将导致任何写该文件的操作都阻塞调用进程直至数据(包括内核I/O缓冲区中的数据)已全部已写至物理存储介质(3.9节)。但如果所写的数据不影响读刚写入的数据,则不等待文件属性更新。

O_RSYNC:如果这一位设置,文件按同步I/O方式打开,并将导致任何读该文件的操作都将等待所有写入同一区域的写操作按O_DSYNC和O_SYNC完成后再进行。如果同时设置了O_SYNC 和 O_RSYNC标志,则读操作将阻塞直到文件的访问时间属性已写至物理存储介质。如果同时设置了O_DSYNC 和 O_RSYNC标志,则读操作将阻塞直到所有与保持文件完整性有关的数据都已写至物理存储介质。

简单地说,O_SYNC、O_DSYNC和O_RSYNC这几个标志的主要作用是使数据直接写到磁盘或直接从磁盘读入。

4. 获取和改变文件状态标签

文件状态标签可以用fcntl()函数获取或改变。如下调用:
fcntl (filedes, F_GETFL, new_flags);

获取描述字 filedes的文件状态标签。它的正常返回值是一个非负整数,此数解释为各个独立标志的按位或。因为文件访问方式不是用独立的位表示的,所以,为比较它们需要用O_ACCMODE屏蔽返回值中的其他位。

例3-5 程序3-5是读取文件状态标签的例子,它打印出指定的文件描述字中已设置了的文件状态标签。为了读取文件访问方式标志,我们先用fcntl()返回的标签值val和O_ACCMODE进行“与”操作,然后再比较其结果。而对于其他标志,则直接从val中抽取。

程序3-5 打印文件状态标签函数
#include "cho3.h"
int display_file_status_flages(int fd)
{
    int accmode, val;
    if ((val = fcntl(fd, F_GETFL, 0) ) < 0)
       err_exit("fcntl error");
    /* 截取文件访问方式标志 */
    accmode = val & O_ACCMODE;
    /* 打印出所有设置了的标志 */
    if (accmode == O_RDONLY)
        printf("read only");
    else if (accmode == O_WRONLY)
        printf( "write only");
    else if (accmode == O_RDWR)
        printf("read write");
    else {
        printf("unknown access mode\n");
        exit(1);
    }
    if (val & O_APPEND)
        printf(" , append");
    if (val & O_NONBLOCK)
        printf(" , nonblocking");
#if !defined(POSIX_SOURCE) && defined(O_SYNC)
     if (val&O_SYNC)
        printf(", synchronous writes" );
#endif
     putchar('\n' );
     exit(0);
}

为了设置描述字filedes的文件状态标签,用命令F_SETFL调用fcntl(),该命令要求int类型的第三个参数以指明新标签:
fcntl (filedes, F_SETFL, new_flags);

它的正常返回值是一个非–1的不确定值。–1指出出错。

文件状态标签中,文件的访问方式是在打开文件时设定的,一旦设定便不能改变;打开时标志只在打开时使用,之后便不再保留。因此,应用唯一可以设置的是文件的I/O操作方式,即O_APPEND、O_NONBLOCK。

同设置文件描述字标签类似,如果想修改文件状态标签,同样应当先用F_GETFL调用fcntl()获得当前标签,然后再修改其值。

例3-6 程序3-6给出的函数保证在设置或清除标志O_NONBLOCK 时不会改变其他标签。

程序3-6 设置文件状态标签为非阻塞方式
#include "ch03.h"
/* 如果value非0,设置desc的O_NONBLOCK标志,否则清除该标志。成功返回0,失败返回-1 */
int set_nonblock_flag (int desc, int value)
{
   int oldflags = fcntl(desc, F_GETFL, 0);
   if(oldflags == -1)    /* 若获取标签失败,返回错误指示 */
       return -1;
    /* 形成并设置新标签 */
   if(value != 0)
       oldflags |= O_NONBLOCK;
   else
       oldflags &= ~O_NONBLOCK;
   return fcntl(desc, F_SETFL, oldflags);
}

抱歉!评论已关闭.