Linux shell创建的每个进程开始时都有三个打开的文件:标准输入(描述符为0)、标准输出(描述符为1)和标准错误(描述符为2)。
改变当前的文件位置。对于每个打开的文件,内核保持着一个文件位置k,初始为0。这个文件位置是从文件开头起始的字节偏移量。
普通文件(regular file)包含任意数据。应用程序常常要区分文本文件(text file)和二进制文件(binary file),文本文件是只含有ASCII或Unicode字符的普通文件;二进制文件是所有其他的文件。对内核而言,文本文件和二进制文件没有区别。
Linux文本文件包含了一个文本行(text line)序列,其中每一行都是一个字符序列,以一个新行符(“
”)结束。
目录(directory)是包含一组链接(link)的文件,其中每个链接都将一个文件名(filename)映射到一个文件,这个文件可能是另一个目录。每个目录至少含有两个条目:“.”是到该目录自身的链接,以及“..”是到目录层次结构中父目录(parent directory)的链接。
套接字(socket)是用来与另一个进程进行跨网络通信的文件。
其他文件类型包含命名通道(named pipe)、符号链接(symbolic link),以及字符和块设备(character and block device)。
Linux内核将所有文件都组织成一个目录层次结构(directory hierarchy),由名为/(斜杠)的根目录确定。系统中的每个文件都是根目录的直接或间接的后代。
作为其上下文的一部分,每个进程都有一个当前工作目录(current working directory)来确定其在目录层次结构中的当前位置。
目录层次结构中的位置用路径名(pathname)来指定。路径名是一个字符串,包括一个可选斜杠,其后紧跟一系列的文件名,文件名之间用斜杠分隔。路径名有两种形式:
绝对路径名(absolute pathname)以一个斜杠开始,表示从根节点开始的路径。
相对路径名(relative pathname)以文件名开始,表示从当前工作目录开始的路径。
一个I/O包,称为RIO(Robust I/O,健壮的I/O)包,它会自动为你处理上下文中所述的不足值。在像网络程序这样容易出现不足值的应用中,RIO包提供了方便、健壮和高效的I/O。RIO提供了两类不同的函数:
无缓冲的输入输出函数。这些函数直接在内存和文件之间传送数据,没有应用级缓冲。
带缓冲的输入函数。这些函数允许你高效的从文件中读取文本行和二进制数据,这些文件的内容缓存在应用级缓冲区内,类似于为printf这样的标准I/O函数提供的缓冲区。
内核用三个相关的数据结构来表示打开的文件:
描述符表(descriptor table)。每个进程都有它独立的描述符表,它的表项是由进程打开的文件描述符来索引的。每个打开的描述符表项指向文件表中的一个表项。
文件表(file table)。打开文件的集合是由一张文件表来表示的,所有的进程共享这张表。每个文件表的表项组成包括当前的文件位置、引用计数(reference count)(即当前指向该表项的描述符表项数),以及一个指向v-node表中对应表项的指针。关闭一个描述符会减少相应的文件表表项中的引用计数。内核不会删除这个文件表表项,直到它的引用计数为零。
v-node表(v-node table)。同文件表一样,所有的进程共享这张v-node表。每个表项包含stat结构中的大多数信息,包括st_mode和st_size成员。