APUE 学习笔记——文件 IO

栏目: IT技术 · 发布时间: 6年前

内容简介:APUE 学习笔记——文件 IO

1、进程创建时,默认打开的文件描述符有哪些?

  • 0: 标准输入
  • 1: 标准输出
  • 2: 标准错误输出

2、创建文件时,参数 oflag 的可选值有哪些?

  • O_RDONLY常量:文件只读打开
  • O_WRONLY常量:文件只写打开
  • O_RDWR常量:文件读、写打开
  • O_EXEC常量:只执行打开
  • O_SEARCH常量:只搜索打开(应用于目录)。本文涉及的操作系统都没有支持该常量

在上面五个常量中必须指定且只能指定一个。下面的常量是可选的(进行或运行):

  • O_CREAT:若此文件不存在则创建它。在使用此选项时,需要同时说明参数mode(指定该文件的访问权限)
  • O_EXCL:若同时指定了O_CREAT时,且文件已存在则出错。根据此可以测试一个文件是否存在。若不存在则创建此文件。这使得测试和创建两者成为一个原子操作
  • O_APPEND:每次写时都追加到文件的尾端
  • O_TRUNC: 如果此文件存在,且为O_WRONLY或者O_RDWR成功打开,则将其长度截断为0
  • O_CLOEXEC
    • 调用 open 函数 O_CLOEXEC 模式打开的文件描述符在执行 exec 调用新程序中关闭,且为原子操作。
    • 调用 open 函数不使用 O_CLOEXEC 模式打开的文件描述符,然后调用 fcntl 函数设置FD_CLOEXEC 选项,效果和使用 O_CLOEXEC 选项 open 函数相同,但分别调用 openfcnt 两个函数,不是原子操作,多线程环境中存在竞态条件,故用 open 函数 O_CLOEXEC 选项代替之。
    • 调用 open 函数 O_CLOEXEC 模式打开的文件描述符,或是使用 fcntl 设置 FD_CLOEXEC 选项,这二者得到(处理)的描述符在通过 fork 调用产生的子进程中均不被关闭。
    • 调用 dup 族类函数得到的新文件描述符将清除 O_CLOEXEC 模式。
      • O_DIRECTORY:若path引用的不是目录,则出错
  • O_NOCTTY:若path引用的是终端设备,则不将该设备分配作为此进程的控制终端
  • O_NOFOLLOW:若path引用的是一个符号链接,则出错
  • O_NONBLOCK:如果path引用的是一个FIFO、一个块特殊文件或者一个字符特殊文件,则文件本次打开操作和后续的 I/O 操作设为非阻塞模式。
  • O_SYNC:每次 write 等待物理 I/O 完成,包括由 write 操作引起的文件属性更新所需的 I/O
  • O_RSYNC:使每一个read操作等待,直到所有对文件同一部分挂起的写操作都完成。
  • O_DSYNC:每次 write 等待物理 I/O 完成,但不包括由 write 操作引起的文件属性更新所需的 I/O ,write 完成后,某些文件属性也不会同步更新。

3、创建文件时,文件的权限( mode )设置有哪些选项?

  • S_IRUSR:用户读
  • S_IWUSR:用户写
  • S_IXUSR:用户执行
  • S_IRGRP:组读
  • S_IWGRP:组写
  • S_IXGRP:组执行
  • S_IROTH:其他读
  • S_IWOTH:其他写
  • S_IXOTH:其他执行

4、文件定位时, whence 的选项有哪些?

SEEK_SET、SEEK_CUR、SEEK_END 三个常量之一 

5、lseek 的注意事项:

  • 打开一个文件时,默认的偏移量是多少?

    除非指定 O_APPEND 选项,否则系统默认将该偏移量设为 0

  • 如果文件描述符指定的是一个管道、FIFO、或者网络套接字,lseek 的结果是什么?

    返回 -1 ,并且将 errno 设置为 ESPIPE

  • lseek 获得的文件偏移量一定是非负数吗?

    对于普通文件,其当前文件偏移量必须是非负值。但是某些设备运行负的偏移量出现。因此比较lseek的结果时,不能根据它小于0 就认为出错。要根据是否等于 -1 来判断是否出错。

  • 当前文件偏移量可以大于文件的当前长度吗?

    当前文件偏移量可以大于文件的当前长度。此时对该文件的下一次写操作将家常该文件,并且在文件中构成一个空洞。空洞中的内容位于文件中但是没有被写过,其字节被读取时都被读为0

6、哪些情况会造成 read 函数实际读到的字节数少于期望读到的字节数?

  • 读普通文件时,在读到期望字节数之前到达了文件尾端
  • 当从终端设备读时,通常一次最多读取一行(终端默认是行缓冲的)
  • 当从某些面向记录的设备(如磁带)中读取时,一次最多返回一条记录
  • 当从网络读时,网络中的缓存机制可能造成返回值小于期望读到的字节数
  • 当从管道或者FIFO读时,若管道包含的字节少于所需的数量,则 read只返回实际可用的字节数
  • 当一个信号造成中断,而已读了部分数据时。

7、进程表现、文件表现、v节点之间的关系?

  • 一个进程打开多个文件:

    APUE 学习笔记——文件 IO

  • 多个进程打开同一个文件:

    APUE 学习笔记——文件 IO

  • 一个进程多次打开同一个文件:

    APUE 学习笔记——文件 IO

    lseek 函数只是修改文件表项中的当前文件偏移量,不进行任何 I/O 操作

8、如何解决多个进程追加一个文件时的竞争关系?

  • 追加一个文件时,不能通过lseek到末尾然后write。要用O_APPEND选项打开文件,然后直接write(通过 O_APPEND 选项打开文件,然后直接write时,内核每一次在写操作之前,都会将进程的当前偏移量设置为 v 节点的偏移量,于是就不需要执行lseek定位操作)
  • pread/pwrite可以执行原子性的定位读/定位写

9、dup2 中如果 fdfd2 相同或者 fd 已经被打开了会发生什么?

  • 如果 fd2 等于 fd,则直接返回 fd2(也等于 fd ),而不作任何操作
  • 如果 fd2 已经是被打开的文件描述符且不等于 fd,则先将其关闭,然后再打开(注意关闭再打开是一个原子操作)

10、syncfsyncfdatasync 的区别?

  • sync:将所有修改过的块缓冲区排入写队列,然后返回,它并不等待时机写磁盘结束
  • fsync:只对由fd指定的单个文件起作用,等待写磁盘操作结束才返回
  • fdatasync:只对由fd指定的单个文件起作用,等待写磁盘操作结束才返回,但是它只影响文件的数据部分(fsync会同步更新文件的属性)

11、fcntlcmd 的选项有哪些?

  • F_DUPFD常量:复制文件描述符 fd。新文件描述符作为函数值返回。它是尚未打开的文件描述符中大于或等于arg中的最小值。新文件描述符与fd共享同一个文件表项,但是新描述符有自己的一套文件描述符标志,其中FD_CLOEXEC文件描述符标志被清除
  • F_DUPFD_CLOEXEC常量:复制文件描述符。新文件描述符作为函数值返回。它是尚未打开的个描述符中大于或等于arg中的最小值。新文件描述符与fd共享同一个文件表项,但是新描述符有自己的一套文件描述符标志,其中FD_CLOEXEC文件描述符标志被设置
  • F_GETFD常量:对应于fd的文件描述符 标志 作为函数值返回。当前只定义了一个文件描述符标志FD_CLOEXEC
  • F_SETFD常量:设置fd的文件描述符标志为arg
  • F_GETFL常量:返回fd的文件状态标志。文件状态标志必须首先用屏蔽字 O_ACCMODE 取得访问方式位,然后与O_RDONLYO_WRONLYO_RDWRO_EXECO_SEARCH比较(这5个值互斥,且并不是各占1位)。剩下的还有:O_APPENDO_NONBLOCKO_SYNC
    O_DSYNCO_RSYNCF_ASYNCO_FSYNC
  • F_SETFL常量:设置fd的文件状态标志为 arg。可以更改的标志是:
    O_APPENDO_NONBLOCKO_SYNCO_DSYNCO_RSYNCF_FSYNCO_ASYNC
  • F_GETOWN常量:获取当前接收 SIGIOSIGURG信号的进程 ID或者进程组 ID
  • F_SETOWN常量:设置当前接收 SIGIOSIGURG信号的进程 ID或者进程组 IDarg。若 arg是个正值,则设定进程 ID;若 arg是个负值,则设定进程组ID
  • F_GETLKF_SETLKF_SETLKW:获取/设置文件记录锁

API

int open(const char* path,int oflag,.../*mode_t mode*/);
int openat(int fd,const char*path,int oflag,.../*mode_t mode */);

int creat(const char*path,mode_t mode);//open(path,O_WRONLY|O_CREAT|O_TRUNC,mode)
int close(int fd);

off_t lseek(int fd, off_t offset,int whence);

ssize_t read(int fd,void *buf,size_t nbytes);
ssize_t write(int fd,const void *buf,size_t nbytes);

ssize_t pread(int fd,void*buf,size_t nbytes,off_t offset);
ssize_t pwrite(int fd,const void*buf,size_t nbytes,off_t offset);

int dup(int fd); //返回的新的文件描述符一定是当前可用的文件描述符中最小的数字
int dup2(int fd,int fd2);

int fsync(int fd);
int fdatasync(int fd);
void sync(void);

int fcntl(int fd,int cmd,.../* int arg */);

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

掘金大数据

掘金大数据

程新洲、朱常波、晁昆 / 机械工业出版社 / 2019-1 / 59.00元

在数据横向融合的时代,充分挖掘数据金矿及盘活数据资产,是企业发展和转型的关键所在。电信运营商以其数据特殊性,必将成为大数据领域的领航者、生力军。各行业的大数据从业者要如何从电信业的大数据中挖掘价值呢? 本书彻底揭开电信运营商数据的神秘面纱,系统介绍了大数据的发展历程,主要的数据挖掘方法,电信运营商在网络运行及业务运营方面的数据资源特征,基于用户、业务、网络、终端及内在联系的电信运营商大数据分......一起来看看 《掘金大数据》 这本书的介绍吧!

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具