第三章 文件I/O

1. 文件描述符
- Unix 系统 shell 把文件描述符 0 与进程的标准输入关联,文件描述符 1 与标准输出关联,文件描述符 2 与标准错误关联;
- 上述 0、1、2 使用时应该替换为符号常量 STDIN_FILENO、STDOUT_FILENO 和 STDERR_FILENO;
- 文件描述符的变化范文是 0 ~ OPEN_MAX - 1;

2. open 和 openat
- 原型:
int open(const char *path, int oflag, …);
int openat(int fd, const char *path, int oflag, …);
- path 参数是要打开或创建文件的名字;
- oflag参数可用来说明此函数的多个选项(oflag参数之间用 “|” 连接);
- open 和 openat 返回的文件描述符一定是最小的未用描述符数值;
- fd 参数:
1) path参数指定的是绝对路径名,fd被忽略,此时俩原型一样;
2) path参数指定的是相对路径名,fd参数表示相对路径名在文件系统中的开始地址;
3) path参数指定的是相对路径名,fd参数具有特殊值AT FDCWD,此时,路径名在当前工作目录中获取;

3. 函数creat
- 原型:
int creat(const char *path, mode_t mode);//成功返回文件描述符,失败返回-1
open(path, O_WRONLY | O_CREAT | O_TRUNC, mode);

4. 函数 close
- 原型:
int close (int fd);
- 当一个进程终止时,内核自动关闭它所有的打开文件。

5. 函数 lseek
- 原型:
off_t lseek(int fd, off_t offset, int whence);//成功返回新的文件偏移量,失败返回-1;
- 功能:显式地为一个打开文件设置偏移量;
- 参数whence:
1) 若whence为SEEK_SET,则偏移量为距文件开始处offset个字节;
2) 若whence为SEEK_CUR,则偏移量为其当前值加offset,offset可正可负;
3) 若whence为SEEK_END,则偏移量为文件长度加offset,offset可正可负;
- 确定打开文件的当前偏移量的方式(也可用来确定所涉及的文件是否可以设置偏移量):
off_t currpos;
currpos = lseek(fd, 0, SEEK_CUR);
- 通常情况下,对于普通文件来讲,偏移量必须是非负值。但由于有些文件允许偏移量为负,所以在判断偏移量是否设置成功时,我们需要判断的是返回值是否等于-1,而非是否小于零。
- 空洞:当文件的偏移量大于文件的当前长度,下一次的写操作将加长该文件,并在文件中构成一个空洞。我的理解是“先占个地”,也就是用空洞来占位置,保证下一次写入是在我们预期的地方。另外,空洞文件可以用来保证多线程的顺利进行,因为这个“占位置”的作用,使同一个任务可以分段写入。

6. 函数 read
- 原型:
ssize_t read ( int fd, void *buf, size_t bnytes);//返回值为读到的字节数,若到文件尾,返回零,出错返回-1;

7. 函数 write
- 原型:
ssize_t write ( int fd, const void *buf, size_t bnytes);//成功返回已写字节数,出错返回-1

8. 内核用三种数据结构表示打开文件
1) 每个进程在进程表中有一个记录项,记录项中包含一张打开文件描述符表;
2) 内核为所有打开文件维持一张文件表;
3) 每个打开文件都有一个v节点(v-node)结构,v 节点包含了文件类型和对此文件进行各种操作函数的指针。(Linux中使用的是i节点,概念相同)
第三章 文件I/O_第1张图片
第三章 文件I/O_第2张图片
9. 原子操作
- 所谓原子操作,指的是一个操作或者一个操作集合,该操作要么执行完,要么不执行;
- 原子操作能够有效避免很多操作间的冲突,比如对文件的修改,如果两个进程对一个文件同时进行操作,或者操作时间差不太多,很有可能出现前一个进程的操作被强行覆盖掉,或者偏移量已经被另一个进程修改之类的错误。
- 函数 pread = lseek + read;但 pread 就是原子操作,一旦调用,无法中断,并且 pread 不更新当前文件偏移量。( pwrite 同理)

10. 函数 dup 和 dup2
- 原型:
int dup ( int fd);
int dup2 ( int fd, int fd2 );
- 作用:复制一个现有的文件描述符;
- dup 返回的是当前可用文件描述符中的最小数值,而 dup2 可以给定新的描述符的值;
- 如果 fd2 已经被占用,则先关闭 fd2(dup2是原子操作,而且可以关别的文件,感觉有点强势);

11. 延迟写
- 延迟写,就是建立一个缓冲区,把写入数据存储到一定程度,一次性写入,避免过于频繁的调用I/O(类似于printf的输出缓冲区);
- sync 函数:将所有修改过的块缓冲区排入写队列,然后返回;
- fsync 函数:只对fd指定的一个文件起作用,并且等到磁盘操作结束才返回;
- fdatasync 函数:同 fsync ,但只影响数据,不同步更新文件属性。

12. 函数 fcntl
- 功能:
1) 复制一个已有的描述符;
2) 获取/设置文件描述符标志;
3) 获取/设置文件状态标志;
4) 获取/设置异步I/O所有权;
5) 获取/设置记录锁;
- 注:修改文件描述符标志或文件状态标志时,先要获得现在的标志值,然后修改,最后设置新的标志值。否则会关闭以前设置的标志位。

13. /dev/fd
- 打开 /dev/fd/n 相当于复制描述符 n。

你可能感兴趣的:(#,UNIX环境高级编程(第三版),c语言,linux)