常规文件(Regular files):是包含有用户信息的文件。包括:C 语言元代码、Shell 脚本、文本文件、图像文件、二进制的可执行文件等。从常规文件读取数据或将数据写入时,内核会根据文件系统的规则执行操作,写入可能被延迟,记录日志或者接受其他操作。一般分为 ASCII 码文件或者二进制文件。
ASCII 码文件:由文本组成。在一些系统中,每行都会用回车符结束(ASCII 码是 13,控制字符 CR,转义字符 \r),另外一些则会使用换行符(ASCII 码是 10,控制字符 LF,转义字符 \n),也有系统(比如 Windows)两者都会使用。ASCII 文件的优点在于显示 和 打印,还可以用任何文本编辑器进行编辑。进一步来说,如果许多应用程序使用 ASCII 码作为输入和输出,那么很容易就能够把多个程序连接起来,一个程序的输出可能是另一个程序的输入,就像管道一样。
二进制文件:取自早期的 UNIX,尽管从技术上来看这个文件只是字节序列,但是操作系统只有在文件格式正确的情况下才会执行。
这个文件有五个段:文件头、正文、数据、重定位位和符号表。文件头以魔数(magic number)开始,表明这个文件是一个可执行文件(以防止意外执行非此格式的文件)。然后是文件各个部分的大小,开始执行的标志以及一些标志位。程序本身的正文和数据在文件头后面,他们被加载到内存中或者重定位会根据重定位位进行判断。符号表则用于调试(e.g. gdb)。
二进制文件的另外一种形式是存档文件,它由已编译但没有链接的库(模块)组合而成。每个文件都以模块头开始,其中记录了名称、创建日期、所有者、保护码和文件大小。和可执行文件一样,模块头也都是二进制数,将它们复制到打印机将会产生乱码。
所有的操作系统必须至少能够识别一种文件类型:它自己的可执行文件。以前的 TOPS-20 系统(用于 DECsystem 20)甚至要检查要执行的任何文件的创建时间,为了定位资源文件来检查自动文件创建后是否被修改过。如果被修改过了,那么就会自动编译文件。在 UNIX 中,就是在 Shell 中嵌入 make 程序。此时操作系统要求用户必须采用固定的文件扩展名,从而确定哪个源程序生成哪个二进制文件。
什么是 make 程序?在软件发展过程中,make 程序是一个自动编译的工具,它通过读取称为 Makefiles 的文件来自动从源代码构建可执行程序和库,该文件指定了如何导出目标程序。尽管集成开发环境和特定语言的编译器功能也可以用于管理构建过程,但 Make 仍被广泛使用,尤其是在 UNIX 和类似 UNIX 的操作系统中使用。
当程序从文件中读写数据时,请求会转到内核处理程序(Kernel driver)。如果文件是常规文件,则数据由文件系统驱动程序处理,并且通常存储在磁盘或其他存储介质上的某块区域中,从文件中读取的数据就是之前在该位置写入的数据。
当数据读取或写入到设备文件时,请求会被设备驱动程序处理。每个设备文件都有一个关联的编号,该编号标示要使用的设备驱动程序。设备处理数据的工作是它自己的事儿。
设备文件:与系统外设相关的,通常在 /dev 下面。分为块设备和字符设备。
字符设备,也称为字符特殊文件(Character special file):和输入/输出有关,用于串行 I/O 类设备,如:终端、打印机、网络等。它的行为类似于管道、串行端口。将字节写入字符设备可能会导致它在屏幕上显示,在串行端口上输出,转换为声音。
块设备,也称为块特殊文件(block special file):用于磁盘类设备。它的行为通常与普通文件相似:它们是字节数组,并且在给定位置读取的值是最后写入该位置的值。来自块设备的数据可以缓存在内存中,并从缓存中读取;写入可以被缓冲。块设备通常是可搜索的,块设备的概念是,相应的硬件可以一次读取或者写入整个块,例如磁盘上的一个扇区。
目录(Directories)是管理文件系统结构的系统文件。它是用于在计算机上存储文,存储文件的唯一地方。目录位于分层文件系统中,例如 Linux,MS-DOS 和 UNIX。
和 DOS 等操作系统不同,Linux 操作系统中单独的文件系统并不是由驱动器号或驱动器名称(e.g. A:、C: 等)来标识的。相反,和 UNIX 操作系统一样,Linux 操作系统将独立的文件系统组合成了一个层次化的树形结构,并且由一个单独的实体代表这一文件系统。Linux 将新的文件系统通过一个称为 “挂装” 或 “挂上” 的操作将其挂装到某个目录上,从而让不同的文件系统结合成为一个整体。
Linux 使用标准的目录结构,在安装的时候,安装程序就已经为用户创建了文件系统和完整而固定的目录结构,并指定了每个目录的作用和其中的文件类型。
完整的目录树可划分为小的部分,这些小部分又可以单独存放在自己的磁盘或分区上。这样,相对稳定的部分和经常变化的部分可单独存放在不同的分区中,从而方便备份或系统管理。
Linux 采用的是树型结构。最上层是根目录,其他的所有目录都是从根目录出发而生成的。在 Linux 中,无论操作系统管理几个磁盘分区,这样的目录树只有一个。从结构上讲,各个磁盘分区上的树型目录不一定是并列的。
文件的构造有多种方式。上图列出了常用的三种构造方式:
上图中的 a 是一种无结构的字节序列,操作系统不关心序列的内容是什么,操作系统能看到的就是字节(Bytes)。其文件内容的任何含义只在用户程序中进行解释。UNIX 和 Windows 都采用这种办法。把文件看成字节序列提供了最大的灵活性。用户程序可以向文件中写任何内容,并且可以通过任何方便的形式命名。操作系统不会为为用户写入内容提供帮助,当然也不会干扰阻塞你。对于想做特殊操作的用户来说,后者是十分重要的。所有的 UNIX 版本(包括 Linux 和 OS X)和 Windows 都使用这种文件模型。
图 b 表示在文件结构上的第一步改进。在这个模型中,文件是具有固定长度记录的序列,每个记录都有其内部结构。把文件作为记录序列的核心思想是:读操作返回一个记录,而写操作重写或者追加一个记录。
第三种文件结构如上图 c 所示。在这种组织结构中,文件由一颗记录树构成,记录树的长度不一定相同,每个记录树都在记录中的固定位置包含一个key 字段。这棵树按 key 进行排序,从而可以对特定的 key 进行快速查找。在记录树的结构中,可以取出下一个记录,但是最关键的还是根据 key 搜索指定的记录。如上图 c 所示,用户可以读出指定的 pony 记录,而不必关心记录在文件中的确切位置。用户也可以在文件中添加新的记录。但是用户不能决定添加到何处位置,添加到何处位置是由操作系统决定的。