第十章-系统级I/O

前言

输入/输出(I/O)是主存和外部设备(列如磁盘驱动器、终端和网络)之间复制数据的过程。输入操作是从I/O设备复制数据到主存,而输出操作是从主存复制数据到I/O设备

10.1 Unix I/O

一个Linux文件就是一个m个字节的序列。

所有的I/O设备(例如网络、磁盘和终端)都被模型化为文件,而所有的输入和输出都被当作对相应文件的读和写来执行。这种将设备优雅地映射为文件的方式,允许Linux内核引出一个简单、低级的应用程序接口,称为Unix I/O,这使得所有的输入和输出都能以一种统一且一致的方式来执行:

  • 打开文件

    • 一个应用程序通过要求内核打开相应的文件,来宣告它想要访问一个I/O设备。
    • 内核返回一个小的非负整数,叫做描述符,它在后续对此文件的所有操作中标识这个文件。内核记录有关这个打开文件的所有信息。应用程序只需记录这个描述符
  • Linux Shell 创建的每个进程开始时都有三个打开的文件:

    • 标准的输入(描述符为0)、
    • 标准输出(描述为1)
    • 标准错误(描述符为2)
  • 改变当前的文件位置

    • 对于每个打开的文件,内核保持着一个文件位置k,初始为0。
    • 这个文件位置是从文件开头起始的字节偏移量
  • 读写文件

    • 一个读操作就是从文件复制n>0个字节到内存,从当前位置k开始,然后将k增加到k+n。
    • 给定一个大小为m字节的文件,当k>=m时执行

10.2 文件

每个Linux文件都有一个类型(type)来表明他在系统中的角色:

  • 普通文件(regular file)

    • 包含任意数据
    • 应用程序常常要区分文本文件(text file)和二进制文件(binary file)
    • 对内核而言,没有区别
  • 目录(directory)

    • 是包含一组链接(link)的文件,其中每个链接都讲一个文件名(filename)映射到一个文件。
    • 这个文件可能是另一个目录
    • 每个目录至少包含有2个条目 1。 ‘.’ 2. ‘..’
  • 套接字(socket)

    • 是用来与另一个进程进行跨网络通宵的文件。

10.3 打开和关闭文件

10.4 读和写文件

10.5 用RIO包健壮地读写

10.6 读取文件元数据

10.7 读取目录内容

10.8 共享文件

文件共享概念。
内核用三个相关的数据结构来表示打开的文件

  • 描述符表(descriptor table)

    • 每个进程都有它独立的描述符表,它的表项是由进程打开的文件描述符来索引的。每个打开的描述符表项指向文件表中的一个表项
  • 文件表(file table)

    • 打开文件的集合是由一张文件表来表示的,所有的进程共享这张表。每个文件表的表项组成(针对我们的目的)包括当前的文件位置、引用计数(reference count)(即当前指向该表项的描述符表项数),以及一个指向v-node表中对应表项的指针。
    • 关闭一个描述符会减少相应的文件表项中的引用计数。内核不会删除这个文件表表项,直到它的引用计数为0
  • v-node表(v-node table)

    • 同文件表一样,所有的进程共享这张v-node表。

10.9 I/O重定向

10.10 标准I/O

标准I/O库将一个打开的文件模型化为一个流。

10.11 综合:我该使用那些I/O函数

10.12 小结