一、C的文件操作
C的文件操作接口
在过去的学习中,我们都已经了解过C语言是有自己的文件操作接口的。当然,不止C有文件操作的接口,C++,pathon等各类编程语言其实也有自己的文件操作接口。而这些语言的文件操作接口函数都是不一样的,使用方法也会有所差异。但是我们要知道,不管这些操作接口如何变化,其归根究底还是需要调用系统的文件操作接口来实现。
原理很简单。我们知道,一台计算机中的文件是存储在它的磁盘中的。而磁盘由OS,即操作系统控制。这就导致无论谁想要访问磁盘,都需要经过操作系统的同意。而我们要进行文件操作,就需要使用OS提供的文件级别的系统接口来访问文件。而一个程序在一台计算机上运行时,只有一个操作系统。
由上面的推导就可以知道,无论上层语言如何变化,其提供的库函数底层都必须要调用系统调用接口。而库函数虽然可以千变万化,但其底层上却是不会变化的,由此,我们可以通过学习系统调用接口来降低我们的学习成本。
2.C的文件操作回顾
在C中,有几个基本的文件操作。即r,w,r+,w+,a等。这几个打开方式都是以文本的方式打开。如果我们想用二进制的方式打开,就可以用r+b,w+b等方式。b代表的就是二进制。
要在C语言下打开和关闭文件,可以使用fopen()和fclose()两个函数
(1)w(写)
w,即write。就是用“只写”的方式打开。该方式下,如果文件不存在,则会自动创建。如果文件存在,则会将文件清空,然后在写入对应的数据
![](https://img-blog.csdnimg.cn/img_convert/463c84aa197295d1984c72510f0d8c87.png)
上面的代码就是以“w”的方式打开一个文件。
![](https://img-blog.csdnimg.cn/img_convert/652c895f14dc5fa7799a7a641db75e33.png)
可以看到,myfile文件运行后,自动生成了一个“file.txt”文件,并且我们用cat命令打开该文件后也可以看到,其成功帮我们在该文件中写入了我们指定的内容
(2)r(读)
r,即以只读的方式打开文件。以该方式打开文件时,如果文件不存在,就会报错
![](https://img-blog.csdnimg.cn/img_convert/11a8fc3fb2f676ca738c625a1bce2f96.png)
现在我们有以上以只读方式打开的代码。该代码会将“file.txt”中的内容存储到tmp数组中,然后再输出该数组中的元素。
在上面的代码中,“sizeof(tmp)-1”是因为fgets()函数会在字符串的末尾自动加上“\0”。因此在将file.txt中的数据写入到tmp中时,在tmp数组中预留一个位置以供该函数的“\0”补齐。
tmp[strlen(tmp)-1]=0则是因为puts()函数默认按行打印,为了防止原数据中存在\n以导致多打印一行,因此将tmp数组中的最后一个元素置为\0
注意,在运行该程序之前,file.txt文件已经存在以“w”方式写好的数据
我们运行该程序:
![](https://img-blog.csdnimg.cn/img_convert/d11dd6d1686293d9706d4d3a01ce47c3.png)
可以看到,此时该程序就直接将file.txt中的内容打印出来了。
(3)a(追加)
a,即以追加的方式打开文件。以这种方式对文件进行写入时,不会清空文件内的数据,而是直接在数据的末尾追加写入
![](https://img-blog.csdnimg.cn/img_convert/16e113f5083143d81529a51a2dbb6316.png)
我们运行两次该程序,再执行“cat file.txt”命令查看该文件中的内容:
![](https://img-blog.csdnimg.cn/img_convert/c74382a0848c3c79aa27b25a9cdbc9dd.png)
可以看到,该程序此时就是执行了两次写入,并且没有清空其中的内容
(4)r+与w+
r+和w+都是以读写的方式打开文件。这两种打开方式的差异体现在是否创建文件。
以r+的方式打开文件时,如果文件不存在,就会报错。而以w+的方式打开文件时,如果文件不存在,就会创建一个文件。
这两种打开文件的方式和结果都很好理解,在这里就不一一展示了。
二、系统底层文件接口操作(以linux为例)
open()函数
![](https://img-blog.csdnimg.cn/img_convert/0743736345b21464407581fc3edac551.png)
该函数是linux下的一个系统层级的文件操作接口,用于文件的打开。在这里面有三个参数。
(1)pathname
pathname指的是要打开的文件的路径,即文件名。
(2)flags
flags是一个标记位。大家可能不是很能理解,我们可以看看对于该函数的描述。
![](https://img-blog.csdnimg.cn/img_convert/9cdd450ed1d6570111af023d7076caec.png)
从这句描述中我们就可以知道,该标记位的作用是标记以何种方式来打开文件。
大家可能还是不太理解为什么要有该标记位。我们以以下程序为大家举例:
![](https://img-blog.csdnimg.cn/img_convert/810b57006485bbdee60d7650f78ddb7f.png)
在该程序中,我们定义了4个宏,这四个宏都是一个标记位。该标记位是通过比特位的方式传递选项。
我们知道,一个int类型的整数是四个字节,即32个比特位。因此,我们使用比特位传递时,将1左移上固定的位数,这样就可以实现该整数的二进制上只有一个1,其余全是0
当我们需要使用固定的选项时,就直接将该选项传入即可。如上图的程序中有ONE、TWO、THREE、FOUR四个选项。在该函数中会将传入的标记位与各个选项按位与,只有传入的flags与选项相同时才会执行
而在上图的程序中,我们将每个选项都执行了一遍。我们运行该程序:
![](https://img-blog.csdnimg.cn/img_convert/e8ee20e2b080af94b51e303140b6a629.png)
可以看到,该程序就按照我们传入的标记位执行了对应的选项。而open()函数中的flags也是一样的作用,