内容简介: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
成功打开,则将其长度截断为0O_CLOEXEC
:- 调用
open
函数O_CLOEXEC
模式打开的文件描述符在执行exec
调用新程序中关闭,且为原子操作。 - 调用
open
函数不使用O_CLOEXEC
模式打开的文件描述符,然后调用fcntl
函数设置FD_CLOEXEC
选项,效果和使用O_CLOEXEC
选项open
函数相同,但分别调用open
、fcnt
两个函数,不是原子操作,多线程环境中存在竞态条件,故用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/OO_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节点之间的关系?
-
一个进程打开多个文件:
-
多个进程打开同一个文件:
-
一个进程多次打开同一个文件:
lseek
函数只是修改文件表项中的当前文件偏移量,不进行任何 I/O 操作
8、如何解决多个进程追加一个文件时的竞争关系?
- 追加一个文件时,不能通过
lseek
到末尾然后write
。要用O_APPEND
选项打开文件,然后直接write
(通过O_APPEND
选项打开文件,然后直接write
时,内核每一次在写操作之前,都会将进程的当前偏移量设置为 v 节点的偏移量,于是就不需要执行lseek
定位操作) pread/pwrite
可以执行原子性的定位读/定位写
9、dup2
中如果 fd
、fd2
相同或者 fd
已经被打开了会发生什么?
- 如果
fd2
等于fd
,则直接返回fd2
(也等于fd
),而不作任何操作 - 如果
fd2
已经是被打开的文件描述符且不等于fd
,则先将其关闭,然后再打开(注意关闭再打开是一个原子操作)
10、sync
、fsync
、fdatasync
的区别?
sync
:将所有修改过的块缓冲区排入写队列,然后返回,它并不等待时机写磁盘结束fsync
:只对由fd
指定的单个文件起作用,等待写磁盘操作结束才返回fdatasync
:只对由fd
指定的单个文件起作用,等待写磁盘操作结束才返回,但是它只影响文件的数据部分(fsync
会同步更新文件的属性)
11、fcntl
中 cmd
的选项有哪些?
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_RDONLY
、O_WRONLY
、O_RDWR
、O_EXEC
、O_SEARCH
比较(这5个值互斥,且并不是各占1位)。剩下的还有:O_APPEND
、O_NONBLOCK
、O_SYNC
、O_DSYNC
、O_RSYNC
、F_ASYNC
、O_FSYNC
F_SETFL
常量:设置fd
的文件状态标志为arg
。可以更改的标志是:O_APPEND
、O_NONBLOCK
、O_SYNC
、O_DSYNC
、O_RSYNC
、F_FSYNC
、O_ASYNC
F_GETOWN
常量:获取当前接收SIGIO
和SIGURG
信号的进程ID
或者进程组ID
F_SETOWN
常量:设置当前接收SIGIO
和SIGURG
信号的进程ID
或者进程组ID
为arg
。若arg
是个正值,则设定进程ID
;若arg
是个负值,则设定进程组ID
F_GETLK
、F_SETLK
、F_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 */);
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- Golang 笔记-文件读写操作
- 笔记-js异步下载文件
- APUE 学习笔记——文件和目录
- python file 文件操作笔记
- Maven学习笔记三【POM文件】
- Android逆向笔记 —— DEX 文件格式解析
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。