当前位置:嗨网首页>书籍在线阅读

01-文件IO

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

第2章 文件I/O

本章以及后续的3个章节将介绍文件相关的内容。UNIX系统主要是通过文件表示的,因此这些章节的探讨会涉及UNIX系统的核心。本章介绍了文件I/O的基本要素,详细阐述了最简单也是最常见的文件交互方式——系统调用。第3章基于标准C库描述标准I/O,第4章继续探讨更高级和专业的文件I/O接口。第8章以文件和目录操作为主题结束了文件相关的探讨。

在对文件进行读写操作之前,首先需要打开文件。内核会为每个进程维护一个打开文件的列表,该列表称为文件表(file table)。文件表是由一些非负整数进行索引,这些非负整数称为文件描述符(file descriptors,简称fds)。列表的每一项是一个打开文件的信息,包括指向该文件索引节点(inode)内存拷贝的指针以及关联的元数据,如文件位置指针和访问模式。用户空间和内核空间都使用文件描述符作为唯一cookies:打开文件会返回文件描述符,而后续操作(读写等)都把文件描述符作为基本参数。

文件描述符使用C语言的int类型表示。没有使用特殊类型来表示文件描述符显得有些怪异,但实际上,这种表示方式正是继承了UNIX传统。每个Linux进程可打开的文件数是有上限的。文件描述符的范围从0开始,到上限值减1。默认情况下,上限值为1 024,但是可以对它进行配置,最大为1 048 576。因为负数不是合法的文件描述符,所以当函数出错不能返回有效的文件描述符时,通常会返回-1。

按照惯例,每个进程都至少包含三个文件描述符:0、1和2,除非显式关闭这些描述符。文件描述符0表示标准输入(sdtin),1表示标准输出(stdout),2表示标准错误(stderr)。Linux C标准库没有直接引用这些整数,而是提供了三个宏,分别是:STDIN_FILENO, STDOUT_FILENO和STDERR_FILENO。一般而言,stdin是连接到终端的输入设备(通常是用户键盘),而stdout和stderr是终端的屏幕。用户可以重定向这些文件描述符,甚至可以通过管道把一个程序的输出作为另一个程序的输入。shell正是通过这种方式实现重定向和管道的。

值得注意的是,文件描述符并非局限于访问普通文件。实际上,文件描述符也可以访问设备文件、管道、快速用户空间互斥(futexes)[1]、先进先出缓冲区(FIFOs)和套接字(socket)。遵循一切皆文件的理念,几乎任何能够读写的东西都可以通过文件描述符来访问。

默认情况下,子进程会维护一份父进程的文件表副本。在该副本中,打开文件列表及其访问模式、当前文件位置以及其他元数据,都和父进程维护的文件表相同,但是存在一点区别:即当子进程关闭一个文件时,不会影响到父进程的文件表。虽然一般情况下子进程会自己持有一份文件表,但是子进程和父进程也可以共享文件表(类似于线程间共享),在第5章将对此进行更详细的介绍。