在 Linux 系统中,文件操作主要分为两种:系统 IO 和 标准 IO。这两种 IO 方式各有特点,适用于不同的场景。
一、系统IO
系统 IO 是指操作系统提供给用户程序调用的一组“特殊”接口,通过这些接口,用户程序可以获得操作系统内核提供的服务。例如,用户程序可以通过进程控制相关的系统调用来创建进程、实现进程调度和进程管理等。
在 Linux 中,为了更好地保护内核空间,将程序的运行空间分为内核空间和用户空间。内核空间和用户空间分别运行在不同的级别上,在逻辑上是相互隔离的。因此,用户进程通常情况下不允许访问内核数据,也无法直接使用内核函数,它们只能在用户空间操作用户数据,调用用户空间的函数。
然而,在某些情况下,用户空间的进程需要获得系统服务(如调用内核空间的程序),这时操作系统必须利用系统提供的“特殊接口”——系统调用,来规定用户进程进入内核空间的具体位置。进行系统调用时,程序运行空间需要从用户空间切换到内核空间,处理完后再返回到用户空间。
Linux 系统调用部分非常精简,大约有 250 个左右,继承了 UNIX 系统调用中最基本和最有用的部分。这些系统调用按照功能逻辑大致可分为以下几类:
- 进程控制:如创建进程、终止进程等。
- 进程间通信:如管道、消息队列、信号量等。
- 文件系统控制:如打开文件、读写文件、关闭文件等。
- 系统控制:如设置系统时间、获取系统信息等。
- 存储管理:如内存分配、内存释放等。
- 网络管理:如网络接口配置、路由管理等。
- socket 控制:如创建 socket、绑定 socket 等。
- 用户管理:如用户认证、用户权限管理等。
系统 IO 没有缓冲机制,它操作的对象是文件描述符。文件描述符是 Unix 系统调用中的一个重要概念。
二、标准IO
标准 IO 是标准库的 I/O 函数,它是对系统调用 IO 进一步封装的结果。标准 IO 具有缓冲机制,这使得 I/O 操作更加高效和灵活。标准 IO 是在标准 C 库中实现的,操作的对象是文件流。
标准 IO 的缓冲机制可以减少实际的系统调用次数,从而提高 I/O 性能。例如,当向文件写入数据时,标准 IO 会先将数据写入缓冲区,当缓冲区满或者遇到特定的刷新操作时,才会将数据写入文件。同样,当从文件读取数据时,标准 IO 会先将数据读入缓冲区,然后从缓冲区中读取数据。
标准 IO 提供了许多方便的函数,如 fopen
、fclose
、fread
、fwrite
等,这些函数封装了底层的系统调用,使得程序员可以更方便地进行文件操作。
三、用户编程接口(API)
在实际编程中,程序员通常使用用户编程接口(API)来进行文件操作。API 是通过软中断机制向内核提交请求,以获取内核服务的接口。然而,并不是所有的 API 函数都一一对应一个系统调用。有时,一个 API 函数需要调用多个系统调用来完成其功能,甚至有些 API 函数不需要调用系统调用。
在 Linux 中,用户编程接口(API)遵循了在 UNIX 中最流行的应用编程界面标准——POSIX 标准。POSIX 标准定义了一组与操作系统交互的接口,使得程序具有更好的可移植性。
四、文件与文件描述符
在 Linux 中,对目录和设备的操作都等同于文件的操作。Linux 中的文件主要分为以下四种:
- 普通文件:包括文本文件和二进制文件。
- 目录文件:用于组织和管理文件。
- 链接文件:指向其他文件的快捷方式。
- 设备文件:用于访问硬件设备。
引用特定的文件是通过文件描述符来实现的。文件描述符是一个非负整数,它是一个索引值,指向内核中每个进程打开文件的记录表。当打开一个现存文件或创建一个新文件时,内核会向进程返回一个文件描述符。当需要读写文件时,需要将文件描述符作为参数传递给相应的函数。
通常,一个进程启动时,都会打开 3 个文件:标准输入、标准输出和标准错误处理。这 3 个文件分别对应文件描述符为 0、1 和 2,也就是宏替换 STDIN_FILENO
、STDOUT_FILENO
和 STDERR_FILENO
。
五、总结
系统 IO 和标准 IO 是 Linux 文件操作的两种主要方式。系统 IO 是直接调用操作系统提供的接口,没有缓冲机制,操作对象是文件描述符。标准 IO 是对系统 IO 的进一步封装,具有缓冲机制,操作对象是文件流。在实际编程中,程序员通常使用用户编程接口(API)来进行文件操作,这些 API 遵循 POSIX 标准,具有良好的可移植性。
通过了解系统 IO 和标准 IO 的区别和特点,程序员可以根据实际需求选择合适的文件操作方式,从而提高程序的性能和可维护性。