《Unix环境高级编程》读书笔记 第3章-文件I/O,unix环境高级编程


1. 引言

  • Unix系统的大多数文件I/O只需用到5个函数:open、read、write、lseek以及close
  • 本章描述的函数经常被称为不带缓冲的I/O。术语不带缓冲指的是在用户的进程中对其不会自动缓冲,每个read和write都调用内核中的一个系统调用。但是,所有磁盘I/O都要经过内核的块缓存区(也称为内核的缓冲区高速缓存)。唯一例外的是对原始磁盘设备的I/O。

2. 文件描述符

  • 对于内核而言,所有打开的文件都通过文件描述符引用。文件描述符是一个非负整数,其变化范围是0~OPEN_MAX-1
  • 惯例:幻数0、1、2分别为符号常量STDIN_FILENO、STDOUT_FILENO、STDERR_FILENO

3. 函数open、openat:创建或打开一个文件

  • oflag参数

  • openat函数是POSIX.1最新版本中新增的一类函数之一,希望解决两个问题:

  • TOCTTOU错误的基本思想是:

    指计算机系统的资料与权限等状态的检查与使用之间,因为特定状态在这段时间已发生改变所产生的软件漏洞

  • 文件名和路径名截断

4. 函数creat:创建一个新文件

  • 等效于 open( path, O_WRONLY | O_CREAT | O_TRUNC, mode );
  • creat的一个不足之处是它以只写方式打开所创建的文件

5. 函数close

  • 关闭一个文件时会释放该进程加在该文件的所有记录锁
  • 当一个进程终止时,内核自动关闭它所有的打开文件

6. 函数lseek:为一个打开文件设置偏移值

  • 每个打开文件(通过open)都有一个与其关联的“当前文件偏移量”。它通常是一个非负整数(有可能为负),用于度量从文件开始处计算的字节数。
  • offse参数的解释与whence参数的值有关:SEEK_SET、SEEK_CUR、SEEK_END
  • 若lseek执行成功,返回新的文件偏移量,故可通过 lseek( fd, 0, SEEK_CUR ); 确定当前偏移量
  • 可用来确定所涉及的文件是否可以设置偏移量,管道、FIFO或网络套接字不可以,lseek返回-1,errno被设置为ESPIPE
  • 名字中的l是在引入off_t类型之前,offset参数和返回值都是long

7. 函数read

  • 读操作从文件的当前偏移处开始,在成功返回之前,该偏移量将增加实际读到的字节数
  • 多种情况下使得读到的字节数少于要求读的字节数

8. 函数write

  • 其返回值通常与参数nbytes的值相同,否则表示错误。
  • 对于普通文件,写操作从文件的当前偏移处开始。如果在打开文件时,指定了O_APPEND选项,则在每次写操作之前,将文件偏移量设置在文件的当前结尾处

9. I/O的效率

  • 大多数文件系统为改善性能都采用某种预读技术

10. 文件共享

  • 内核使用3种数据结构表示打开文件,它们之间的关系决定了在文件共享方面一个进程对另一个进程可能产生的影响

    左边:进程级的文件描述符表

  • 中间:系统级的打开文件表:每次调用open打开一个文件新增一个文件表项(不同进程可打开同一个文件,导致多个文件表项)

  • 右边:文件系统级的i-node表

  • 其他

11. 原子操作

  • 先lseek再write,不等价于,指定了O_APPEND的write
  • 对open函数指定O_CREAT和O_EXCL

  • 函数pread、pwrite

  • 调用pread相当于调用lseek后调用read,但又有区别:

  • 调用pwrite相当于调用lseek后调用write,也有类似的区别

12. 函数dup、dup2

  • dup返回的新文件描述符一定是当前可用文件描述符的最小数值
  • dup2可以用fd2参数指定新描述符的值

  • dup(fd); 等价于 fcntl(fd, F_DUPFD, 0);

  • dup2(fd, fd2); 不完全等价于 close(fd2); fcntl(fd, F_DUPFD, fd2); 因为其非原子操作,且dup2和fcntl有一些不同的errno

13. sync、fsync、fdatasync

  • 传统的Unix系统实现在内核中设有缓冲区高速缓存或页高速缓存,大多数磁盘I/O都通过缓冲区进行。当我们向文件写入数据时,内核通常先将数据复制到缓冲区中,然后排入队列,晚些时候再写入磁盘。这种方式被称为延迟写

14. 函数fcntl:改变已打开文件的属性

  • fcntl函数有以下5种功能

  • 先通过GET获取得到val,再 val |= flags; 或 val &= ~flags; 最后通过SET将val设置到fd

15. 函数ioctl

  • 通常有另外一个参数,它常常是指向一个变量或结构的指针
  • 上面原型中只include了ioctl函数本身需要的头文件。通常,需要另外的设备专用头文件,如:终端I/O的ioctl命令都需要头文件termios.h

16. /dev/fd

  • 打开文件/dev/fd/n等效于复制描述符n(假设描述符n是打开的)
  • Linux实现中的/dev/fd是个例外,它把文件描述符映射成指向底层物理文件的符号链接,例如,当打开/dev/fd/0时,事实上正在打开与标准输入关联的文件

[wulin@localhost ~]$ ls /dev/fd/ -l
lrwx------. 1 wulin wulin 64 7月 29 10:28 0 -> /dev/pts/0
lrwx------. 1 wulin wulin 64 7月 29 10:28 1 -> /dev/pts/0
lrwx------. 1 wulin wulin 64 7月 29 10:28 2 -> /dev/pts/0
lr-x------. 1 wulin wulin 64 7月 29 10:28 3 -> /proc/5341/fd

[wulin@localhost ~]$ ls /dev/std* -l
lrwxrwxrwx. 1 root root 15 7月 29 2014 /dev/stderr -> /proc/self/fd/2
lrwxrwxrwx. 1 root root 15 7月 29 2014 /dev/stdin -> /proc/self/fd/0
lrwxrwxrwx. 1 root root 15 7月 29 2014 /dev/stdout -> /proc/self/fd/1

  • /dev/fd文件主要由shell使用,它允许使用路径名作为调用参数的程序,能用处理其他路径名的相同方式处理标准输入和输出。
  • filter file2 | cat file1 - file3 | lpr 首先cat读file1,然后读其标准输入(filter file2命令的输出),然后读file3
  • 如果支持/dev/fd,则可以删除cat对“-”的特殊处理,于是可以: filter file2 | cat file1 /dev/fd/0 file3 | lpr
  • 作为命令后参数的“-”特指标准输入或标准输出,这已被很多程序采用。但是这会带来一些问题,例如,如果用“-”指定第一个文件,那么看来就像指定了命令行的一个选项

在linux下怎使用《UNIX环境高级编程》里面的“ourhdrh“这文件?

未定义。。。。
blog.csdn.net/xuorui/article/details/5447555
其实就是源码的编译和include
看看上面的网站能否解决
如果 无法解决
g o o g l e
apue源码编译
作者写的头文件么 。。。
 

谁好的linux学习网站,分享一些

verycd上很多教程 linuxsir上也有很多文章
 

相关内容