【Linux】浅谈文件原理与操作 您所在的位置:网站首页 打开文件操作文件关闭文件c语言 【Linux】浅谈文件原理与操作

【Linux】浅谈文件原理与操作

2023-06-14 10:37| 来源: 网络整理| 查看: 265

目录

问题引入

浅谈文件原理

文件操作

文件的打开与关闭

open

close

write与read

再谈C库文件操作

问题引入

🌸以前我们学过C语言的文件操作,而不同语言的文件操作都是不一样的,我们该如何理解这一现象,能不能用一种统一的视角看待所有文件操作?今天就一起来谈谈文件操作。

浅谈文件原理

我们都知道,文件 = 内容 + 属性,对于一个文件的操作可以看成对内容或属性的操作。

通过冯诺依曼体系我们知道当我们对文件进行操作时,该文件一定处于内存之中,而未被进行操作的文件则位于磁盘里。

在操作系统看来,文件便可以被分成两大类:磁盘文件和被打开文件。

🌸其中被打开文件至少需要将文件属性加载到内存之中,而每次文件操作前我们都要先打开文件的本质就是:将目标文件属性加载到内存中。因此,OS内部一定会同时存在大量的被打开的文件。需要将其以先描述再组织的方式管理起来。

这样在OS内部对于打开文件的管理就转换成了对链表的增删查改。即文件被打开前,OS要为被打开文件创建内核数据结构 struct file。

🌸那么文件是被谁打开的呢?

用户通过调用进程完成打开文件的操作

如此解释后,我们对于文件又有进一步的认识,下面我们来介绍一下在OS层面文件操作的系统接口。

文件操作

🌸对C语言文件操作不熟悉或有些忘记了的,也可以看看这篇复习一下:C语言文件操作的基础应用。

文件的打开与关闭 open

🌸通过手册查询,我们可以找到 open 函数的相关信息,其中的参数分别是文件路径和打开文件的选项。

🌸其中的 flag ,我们不能将其看成一个整数而是将其看作一个位图。

🌸其中每一个位置都代表一个选项,为 1 则表示选中反之不选,库中定义了宏方便我们直接使用。

O_WRONLY  只写选项O_RDONLY   只读选项O_APPEND   追加写入O_TRUNC     打开时清空文件O_CREAT      若文件不存在则创建O_RDWR       支持同时读写

🌸在使用时使用 | 操作符标记位图的对应位置即可。

int main() { open("log.txt", O_WRONLY | O_TRUNC | O_CREAT); //以只读每次打开清空文件若不存在则创建新文件的方式打开 return 0; }

🌸这时候,我们便会发现现在的这个操作跟 fopen 十分的相似,只不过将 w 选项拆成了三个选项。其实,fopen 的底层便是调用了这个系统调用进行文件的打开操作。

🌸虽然我们成功创建出一个文件了,但此时我们可以看到,该文件的权限却是乱码,因此在创建文件时我们就需要手动设置文件的权限。

🌸open 还重载了三个参数的版本,供我们设置文件权限。

int main() { open("log.txt", O_WRONLY | O_TRUNC | O_CREAT,0666); return 0; }

 

🌸这下创建出来的就是正常权限的文件了,但是却与我们设置的 0666 不一样而是 0664 呢?这是由于文件的权限还受到权限掩码的影响,因此需要将 umask 置零。

int main() { umask(0); open("log.txt", O_WRONLY | O_TRUNC | O_CREAT,0666); return 0; }

🌸这下就根据我们要求创建出对应权限的文件了。

🌸而  open 有一个返回值,我们刚才忽略掉了,其为文件描述符又名 fd,我们需要定义一个变量接收一下它,之后需要用它定位文件。

🌸若 fd 为 -1 说明打开文件失败,我们可以在打开文件后增加一个判断。

int main() { umask(0); int fd = open("log.txt", O_WRONLY | O_TRUNC | O_CREAT,0666); if(fd == -1) { printf("fd: %d,errstring is: %s\n",fd,strerror(errno)); } return 0; } close

🌸关闭文件就需要我们上面存起来的 fd 了,直接传入 fd 即可关闭文件。

int main() { umask(0); int fd = open("log.txt", O_WRONLY | O_TRUNC | O_CREAT,0666); if(fd == -1) { printf("fd: %d,errstring is: %s\n",fd,strerror(errno)); } close(fd); return 0; } write与read

🌸打开文件后我们就可以根据需求对文件进行读写了,先介绍 write 接口。

🌸参数分别是 fd,写入内容的字符串和写入的字节数,写入后返回写入的字节数,失败则返回 -1。

🌸这里我先将用 snprintf 内容格式化写入一个字符串中,再写到文件里。

int main() { umask(0); int fd = open("log.txt", O_WRONLY | O_TRUNC | O_CREAT,0666); if(fd == -1) { printf("fd: %d,errstring is: %s\n",fd,strerror(errno)); } const char* ptr = "helloworld"; //原字符串 char str[20]; //转接的字符数组 int i = 1; snprintf(str,sizeof(str),"%s: %d",ptr,i); //加个序号格式化写入 write(fd,str,strlen(str)); //写入文件 close(fd); //关闭文件 return 0; }

[注意]:\0 是C语言库中的设定,直接写入到文件中会被识别成乱码,使用 write 写入时要注意不写入 \0。因此写入时直接使用 strlen 便可以自动规避掉 \0。

🌸之后我们来看读取的操作,需要传入 fd 定位文件,之后将文件内的数据读入数组中,读取 count 个字节。

🌸成功读取后会返回读取的字节数,若读取失败则会返回 -1。

🌸这次我们以读取的方式打开文件,由于不用创建文件因此就不需要手动设置文件权限了。

int main() { int fd = open("log.txt", O_RDONLY); //只读打开文件 char buffer[1024]; size_t n = read(fd, buffer, sizeof(buffer) - 1); //为\0留一个位置 if (n > 0) //说明读入数据 { buffer[n] = '\0'; //在数据尾部插入\0 printf("%s\n", buffer); //打印出数据内容 } return 0; }

🌸同时为了方便接下来的读写,读取需要为 \0 预留一个位置,之后再加上即可。

再谈C库文件操作

🌸在上面我们就说过C库文件操作的底层本质上也是调用了操作系统提供的系统调用,即库函数只是对系统调用的封装。

🌸那又是为什么呢?我们可以用下面这张图简单理清几者之间的关系。

🌸只要涉及文件操作,就与文件读写分不开关系,在读写的过程中便会涉及到对硬件的访问,而硬件是由操作系统进行管理的。因此从用户层面出发,只要访问到硬件就无法绕开操作系统。

🌸不仅只是C语言,任何语言的文件操作都是对系统调用的封装,都是借助系统接口才能够实现!!!

🌸好了,今天 浅谈文件原理与操作 的相关内容到这里就结束了,如果这篇文章对你有用的话还请留下你的三连加关注。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有