1.输入和输出(I/O)
输入和输出(I/O)是在主存和外部设备(例如磁盘驱动器、终端和网络)之间复制数据的过程。输入操作是从I/O设备复制数据到主存,而输出操作是从主存复制数据到I/O设备。
所以语言运行时系统都提供执行I/O的较高级别的工具。例如,ANSI C提供标准I/O库,包含像printf和scanf这样执行带缓冲区的I/O函数。C++语言用它的重载操作符<<(输入)和>>(输出)提供了类似的功能。在linux系统中,是通过使用由内核通过的系统级unix I/O函数来实现这些较高级别的I/O函数的。大多数时候,高级别I/O函数工作良好,没有必要直接使用unix I/O。
2.文件
每个Linux文件都有一个类型(type)来表明它在系统中的角色。
-->普通文件(regular file):包含任何数据。应用程序常常要区分文本文件(text file)和二进制文件(binary file),文本文件是只含有ASCII或Unicode字符的普通文件;二进制文件是所有其他的文件。对内核而言,文本文件和二进制文件没有区别。linux文本文件包含了一个文本行(text line)序列,其中每一行都是一个字符序列,以一个新行符('\n')结束。新行符与ASCII的转行符(LF)是一样的,其数字值为0x0a。
-->目录(directory):是包含一组链接(link)的文件。其中每个链接都将一个文件名(filename)映射到一个文件,这个文件可能是另一个目录。每个目录至少包含两个条目:‘.'是到该目录自身的链接,以及'..'是到目录结构层次中父目录(parent directory)的链接。你可以用mkdir命令创建一个目录,用ls查看其内容,用rmdir删除该目录。
-->套接字(socket):是用来与另一个进程进行跨网络通信的文件。
其他文件类型包含命名通道(named pipe)、符号链接(symbolic link)以及字符和块设备(charactor and block device)。
Linux内核将所有文件都组织成一个目录层次结构(directory hierarchy),由名为/(斜线)的根目录确定。系统中的每个文件都是根目录的直接或间接的后代,如下图,
目录层次结构中的位置用路径名(filename)来指定。路径名是一个字符串,包括一个可选斜杠,其后紧随一系列的文件名,文件名之间用斜杠分隔。路径名有两种形式:
-->绝对路径名(absolute filename):以一个斜杠开始,表示从根节点开始的路径。如上图,hello.c的绝对路径名为/home/droh/hello.c。
-->相对路径名(relative filename):以文件名开始,表示从当前工作目录开始的路径。如上图,如果/home/droh是当前的工作目录,那么hello.c的相对路径名为./hello.c;如果/home/bryant是当前的工作目录,那么相对路径名就是../home/droh/hello.c。
3.打开和关闭文件
进程是通过调用open函数来打开一个已存在的文件或者创建一个新文件。
4.读和写文件
应用程序是通过分别调用read和write函数来执行输入和输出。
5.用RIO包健壮地读写
RIO提供了两类不同的函数。
-->无缓冲的输入输出函数:这些函数直接在内存和文件之间传送数据,没有应用级缓冲。它们对将二进制数据读写到网络和从网络读写二进制数据尤其有用。
-->带缓冲的输入函数:这些函数允许高效地从文件中读取文本行和二进制数据,这些文件的内容缓存在应用级缓冲区内,类似于为printf这样的标准I/O函数提供的缓冲区。与带缓冲的I/O例程不同,带缓冲的RIO输入函数是线程安全的,它在同一个描述符上可以被交错的调用。例如,你可以从一个描述符中读取一些文本行,然后读取一些二进制数据,接着再多读取一些文本行。
6.读取文件元数据
应用进程能够通过调用stat和fstat函数,检索到关于文件的信息(有时也称为文件的元数据(metadata))。
7.读取目录内容
应用程序可以用readdir序列函数来读取目录的内容。
8.共享文件
可以用许多不同的方式来共享Linux文件。除非你很清楚内核是如何表示打开的文件,否则文件共享的概念相当难懂。内核用三个相关的数据结构来表示打开的文件。
-->描述符表(descriptor table):每个进程都有它独立的描述符表,它的表项是由进程打开的文件描述符来索引的。每个打开的描述符表项指向文件表中的一个表项。
-->文件表(file table):打开文件的集合是由一张文件表来表示的,所有的进程共享这张表。每个文件表的表项组成包括当前的位置、引用计数,以及一个指向v-node表中对应表项的指针。关闭一个描述符会减少相应的文件表表项中的引用计数。内核不会删除这个文件表表项,直到它的引用计数为零。
-->v-node表(v-node table):同文件表一样,所有的进程共享这张v-node表。每个表项包含stat结构中的大多数信息,包括st_mode和st_size成员。
9.I/O重定向
Linux shell提供了I/O重定向操作符,允许用户将磁盘文件和标准输入输出联系起来。
例如,键入:linux > ls > foo.txt
使得shell加载和执行ls程序,将标准输出重定向到磁盘文件foo.txt。
实现方式,通过使用dup2函数。
10.标准I/O
C语言定义了一组高级输入输出函数,称为标准I/O库,为程序员提供了Unix I/O的较高级别的替代。这个库(libc)提供了打开和关闭文件的函数(fopen和fclose)、读和写字节的函数(fread和fwrite)、读和写字符串的函数(fgets和fputs),以及复杂的格式化的I/O函数(scanf和printf)。
标准I/O库将一个打开的文件模型化为一个流,对于程序员而言,一个流就是一个指向FILE类型的结构的指针。每个ANSI C程序开始时都有三个打开的流(stdin、stdout、stderr,分别对应于标准输入、标准输出和标准错误)。
第十章小结