zoukankan      html  css  js  c++  java
  • TLPI读书笔记第4章-文件IO2

    4.2 通用IO

    UNIX I/O 模型的显著特点之一是其输入/输出的通用性概念。这意味着使用 4 个同样的系统调用 open()、 read()、 write()和 close()可以对所有类型的文件执行 I/O 操作,包括终端之类的设备。

    4.3 打开一个文件:open()

    open()调用既能打开一个业已存在的文件,也能创建并打开一个新文件

    要打开的文件由参数 pathname 来标识。如果 pathname 是一符号链接,会对其进行解引用。 如果调用成功, open()将返回一文件描述符,用于在后续函数调用中指代该文件。若发生错误, 则返回-1,并将 errno 置为相应的错误标志。 参数 flags 为位掩码,用于指定文件的访问模式

    当调用 open()创建新文件时,位掩码参数 mode 指定了文件的访问权限。如果 open()并未指定 O_CREAT 标志,则可以省略 mode 参数

    SUSv3 规定,如果调用 open()成功,必须保证其返回值为进程未用文件描述符中数值最小者。

    4.3.1 open()调用的flags参数

     

     

    常量分为如下几组。

    文件访问模式标志:

    先前描述的 O_RDONLY、 O_WRONLY 和 O_RDWR 标志均在此列,调用 open()时,上述三者在 flags 参数中不能同时使用,只能指定其中一种。调用fcntl()的 F_GETFL 操作能够检索文件的访问模式

    文件创建标志:

    这些标志在表 4-3 中位于第二部分,其控制范围不拘于 open()调用行为的方方面面,还涉及后续 I/O 操作的各个选项。这些标志不能检索,也无法修改。

    已打开文件的状态标志:

    这些标志是表 4-3 中的剩余部分,使用 fcntl()的 F_GETFL 和SETFL 操作可以分别检索和修改此类标志。有时干脆将其称之为文件状态标志。

    flags常量详细描述

    O_APPEND 总是在文件尾部追加数据

    O_ASYNC 当对于 open()调用所返回的文件描述符可以实施 I/O 操作时,系统会产生一个信号通知进程。这一特性,也被称为信号驱动 I/O,仅对特定类型的文件有效,诸如终端、 FIFOS 及 socket。在 Linux 中,调用 open()时指定 O_ASYNC 标志没有任何实质效果。要启用信号驱动 I/O 特性,必须调用 fcntl()的 F_SETFL 操作来设置 O_ASYNC 标志,关于 O_ASYNC 标志的更多内容请参考 63.3 节。

    O_CLOEXEC 为新(创建)的文件描述符启用 close-on-flag 标志( FD_CLOEXEC)。 27.4 节将描述 FD_CLOEXEC 标志。使用 O_CLOEXEC 标志(打开文件),可以免去程序执行 fcntl()的 F_GETFD和 F_SETFD 操作来设置 close-on-exec 标志的额外工作。在多线程程序中执行 fcntl() 的 F_GETFD和 F_SETFD 操作可能导致竞争状态,而使用O_CLOEXEC 标志则能够避免这一点。可能引发竞争的场景是:线程某甲打开一文件描述符,尝试为该描述符标记 close-on-exec 标志,于此同时,线程某乙执行 fork()调用,然后调用 exec()执行任意一个程序。(假设在某甲打开文件描述符和调 fcntl()设置 close-on-exec 标志之间,某乙成功地执行了 fork()和 exec()操作。)此类竞争可能会在无 意间将打开的文件描述符泄露给不安全的程序。

    O_CREAT 如果文件不存在,将创建一个新的空文件。即使文件以只读方式打开,此标志依然有效。如果在 open()调用中指定 O_CREAT 标志,那么还需要提供 mode 参数,否则,会将新文件的权限设置为栈中的某个随机值。

    O_DIRECT 无系统缓冲的文件 I/O 操作。该特性将在 13.6 节中详述。为使 O_DIRECT 标志的常量定义在<fcntl.h>中有效,必须定义GNU_SOURCE 功能测试宏。

    O_DIRECTORY 如果 pathname 参数并非目录,将返回错误(错误号 errno 为 ENOTDIR)。这一标志是专为实现 opendir()函数而设计的扩展标志。为使 O_DIRECTORY 标志的常量定义在<fcntl.h>中有效,必须定义GNU_SOURCE 功能测试宏。

    O_DSYNC 根据同步 I/O 数据完整性的完成要求1来执行文件写操作。参见 13.3 节中关于内核 I/O 缓冲的讨论。

    O_EXCL 此标志与 O_CREAT 标志结合使用表明如果文件已经存在,则不会打开文件,且 open()调用失败,并返回错误,错误号 errno 为 EEXIST。换言之,此标志确保了调用者(open( )的调用进程)就是创建文件的进程。检查文件存在与否和创建文件这两步属于原子操作,如果在 flags 参数中同时指定了 O_CREAT 和 O_EXCL 标志,且pathname 参数是符号链接,则 open()函数调用失败(错误号 errno 为 EEXIST)。 SUSv3 之所以如此规定,是要求有特权的应用程序在已知目录下创建文件,从而消除了如下安全隐患,使用符号链接打开文件会导致在另一位置创建文件(例如,系统目录)。

    O_LARGEFILE 支持以大文件方式打开文件。在 32 位操作系统中使用此标志,以支持大文件操作。尽管 在 SUSv3 中没有规定这一标志,但其他一些 UNIX 实现都支持这一特性。此标志在诸如 Alpha、 IA-64 之类的 64 位 Linux 实现中是无效的。更多的内容将在 5.10 节中讨论。

    O_NOATIME 在读文件时,不更新文件的最近访问时间( 15.1 节中所描述的 st_atime 属性)。要使用该标志,要么调用进程的有效用户 ID 必须与文件的拥有者相匹配,要么进程需要拥有特权( CAP_FOWNER)。否则, open()调用失败,并返回错误,错误号 errno 为 EPERM。 (事实上,如 9.5 节所述,对于非特权进程,当以 O_NOATIME 标志打开文件时,与文件用户 ID 必须匹配的是进程的文件系统用户 ID,而非进程的有效用户 ID。 )此标志是 Linux 特有的非标准扩展。要从<fcntl.h>中启用此标志,必须定义_GNU_SOURCE 功能测试宏。 O_NOATIME 标志的设计旨在为索引和备份程序服务。该标志的使用能够显著减少磁盘的活动量,省却了要读取文件内容,又要更新文件 i-node 结构中最近访问时间的繁琐,进而节省了磁头在磁盘上的反复寻道时间(14.4 节)。 mount()函数中 MS NOATIME 标志(14.8.1 节)和 FS_NOATIME_FL 标志( 15.5 节)与 O_NOATIME 标志功能相似。

    O_NOCTTY 如果正在打开的文件属于终端设备, O_NOCTTY 标志防止其成为控制终端。如果正在打开的文件不是终端设备,则此标志无效。

    O_NOFOLLOW 通常,如果 pathname 参数是符号链接, open()函数将对 pathname 参数进行解引用。一旦在 open()函数中指定了 O_NOFOLLOW 标志,且 pathname 参数属于符号链接,则 open()函数将返回失败(错误号 errno 为 ELOOP)。此标志在特权程序中极为有用,能够确保 open()函数不对符号链接进行解引用。为使 O_NOFOLLOW 标志在<fcntl.h>中有效,必须定义_GNU_SOURCE 功能测试宏。

    O_NONBLOCK 以非阻塞方式打开文件。

    O_SYNC 以同步 I/O 方式打开文件。

    O_TRUNC 如果文件已经存在且为普通文件,那么将清空文件内容,将其长度置 0。在 Linux 下使用此标志,无论以读、写方式打开文件,都可清空文件内容。 SUSv3 对 O_RDONLY 与 O_TRUNC 标志的组合未作规定,但多数其他 UNIX 实现与 Linux 的处理方式相同

    4.3.2 open函数的错误

    若打开文件时发生错误, open()将返回-1,错误号 errno 标识错误原因。以下是一些可能 发生的错误(除了在上节参数描述中已经提及的错误之外)。

    EACCES 文件权限不允许调用进程以 flags 参数指定的方式打开文件。无法访问文件,其可能的原 因有目录权限的限制、文件不存在并且也无法创建该文件。

    EISDIR 所指定的文件属于目录,而调用者企图打开该文件进行写操作。不允许这种用法。(另一 方面,在某些场合中,打开目录进行读操作是必要的。 18.11 节将举例说明。 )

    EMFILE 进程已打开的文件描述符数量达到了进程资源限制所设定的上限(在 36.3 节将描述

    RLIMIT NOFILE 参数)。

    ENFILE 文件打开数量已经达到系统允许的上限。

    ENOENT 要么文件不存在且未指定 O_CREAT 标志,要么指定了 O_CREAT 标志,但 pathname 参 数所指定路径的目录之一不存在,或者 pathname 参数为符号链接,而该链接指向的文件不存 在(空链接)。

    EROFS 所指定的文件隶属于只读文件系统,而调用者企图以写方式打开文件。

    ETXTBSY 所指定的文件为可执行文件(程序),且正在运行。系统不允许修改正在运行的程序(比如 以写方式打开文件)。 (必须首先终止程序运行,然后方可修改可执行文件。 ) 后续在描述其他系统调用或库函数时, 一般不会再以上述方式展现可能发生的一系列错 误。(每个系统调用或库函数的错误列表可从相关操作手册中查询获得。 )采用上述方式原因 有二,一是因为 open()是本书详细描述的首个系统调用,而上述列表表明任一原因都有可能 导致系统调用或库函数的调用失败。二是 open()调用失败的具体原因列表本身就颇为值得玩 味,它展示了影响文件访问的若干因素,以及访问文件时系统所执行的一系列检查。 (上述 错误列表并不完整,更多 open()调用失败的错误原因请查看 open(2)的操作手册。

    4.3.3 creat()系统调用

    在早期的 UNIX 实现中, open()只有两个参数,无法创建新文件,而是使用 creat()系统调用来创建并打开一个新文件。

    creat()系统调用根据 pathname 参数创建并打开一个文件,若文件已存在,则打开文件,并清空文件内容,将其长度清 0。 creat()返回一文件描述符,供后续系统调用使用。 尽管 creat()在一些老旧程序的代码中还时有所见,但由于 open()的 flags 参数能对文件打开方式提供更多控制(例如:可以指定 O_RDWR 标志,代替 O_WRONLY 标志),对 creat()的使用现在已不多见

  • 相关阅读:
    Eclipse中添加MyEclipse插件
    用GWT开发的HelloGWT程序
    GWT module 'xxx' may need to be (re)compiled解决办法
    GWTDesigner_v5.1.0破解码
    Firefox火狐广告过滤插件Adblock Plus过滤规则包[中文维护小组]
    工程师们,不要想一辈子靠技术混饭吃
    PHP生成类似类似优酷、腾讯视频等其他视频链的ID
    (外挂破解)Cheat Engine(内存修改工具)V6.2中文版软件介绍
    ucos-ii核心算法分析(转)
    Websocket,ProtoBuffer,Hightlight,JSON 等,最近遇到的一些知识点小结
  • 原文地址:https://www.cnblogs.com/wangbin2188/p/14628264.html
Copyright © 2011-2022 走看看