Linux文件(一).前传之基础IO

一.理解文件

1.狭义理解

①.文件=内容+属性。

②.文件储存在磁盘上。

③.磁盘是永久性存储介质,因此⽂件在磁盘上的存储是永久性的。

④.磁盘是外设(即是输出设备也是输⼊设备)。

⑤. 磁盘上的⽂件本质是对⽂件的所有操作,都是对外设的输⼊和输出简称IO。

2.广义理解文件

Linux下**⼀切皆⽂件**(键盘、显⽰器、⽹卡、磁盘......这些都是抽象化的过程)。

3.文件 = 内容 + 属性

①.对于0KB的空⽂件是占⽤磁盘空间的,空文件也具有属性,也要占空间!

②.⽂件是⽂件属性(元数据)和⽂件内容的集合(⽂件=属性(元数据)+内容)。

③. 所有的⽂件操作本质是**⽂件内容操作和⽂件属性操作。**

4.系统角度

任何文件都必须先打开,然后才能访问!! 那么是谁打开了文件呢?答案是进程 。所以文件操作的本质是进程对文件进行操作。

既然涉及到进程,就事关OS,也就是说想要访问文件(文件储存在磁盘),就是访问磁盘,而管理磁盘的正是OS,所以访问文件,其实是去调用OS的接口

二.回顾

1.如何将信息输出到显示器

向显示器打印数据,本质上就是对显示器这个文件进行写入(linux下一切皆文件!)。

2.stdin & stdout &stderr

这是三个文件流,是FILE类型的指针,分别代表键盘文件显示器文件。c语言程序在启动的时候,默认会打开这三个输入输出流(打开指向的文件)。

那么为何要默认打开输入输出流呢?

程序运行几乎一定有输入输出 ,如果每次写程序都要用fopen+打开方式去打开文件,代码会十分繁琐和冗余。就比如使用基础IO函数时,需要手动打开文件,那么每写一个helloworld或者用scanf获取一段数据,都需要去手动打开屏幕文件和显示器文件,特别麻烦。

3.文件打开的方式

①.w

以w(写)的方式打开文件时,默认会先将文件的内容清空

这里就能解释,为什么用">"(重定向操作符)向文件写入内容时,每写一次进去,就把原来的东西覆盖掉一次。使用">"时,默认会先以写(w)的方式打开文件,就会清空原来文件里的内容。

②.a

用这种方式打开的文件,在写入数据时,玩的是追加(向文件结尾处追加),也就是说不会想上面那样每打开一次文件,就清空一次文件内容。

在使用">>"(追加重定向操作符)写入数据时,会默认先以"a"的方式打开文件,因此写入的数据是追加的:

三.系统文件IO

打开⽂件的⽅式不仅仅是fopen,ifstream等流式,语⾔层的⽅案,其实系统才是打开⽂件最底层的⽅ 案。

1.open

就比如fopen是语言层面的接口,当调用fopen时,fopen其实还会去调用系统调用接口open。open的参数列表里有一个flags标记位,我们先来明晰何谓标志位。

①.标志位

flags是一个整型的数据,是宏。

flags的几个宏

把这些宏传入open,可以让文件以不同方式被打开,这也是语言层面fopen里"w","r"等打开方式的实现原理。

来看一下各个宏的作用:

·O_RDONLY:只读打开·OWRONLY:只写打开

·O_RDWR:读写打开

·O_CREAT:若文件不存在则创建

·O_TRUNC:打开文件的同时清空文件内容

(Truncate)

·O_APPEND:追加写模式

这些宏是可以组合使用的,在传参的时候用"|"连接就行了。

fopen的"w"和"a"打开方式的底层:

2.文件描述符fd到底是个什么鬼?

①.类型角度

通 过对open函数的学习,我们知道了⽂件描述符就是**⼀个⼩整数,是open的返回值。**

这里有个奇怪的现象:当我们用open打开多个文件,并打印它们对应的fd时,怎么从3开始,那么0,1,2去哪了呢?

答案是Linux进程默认情况下会有3个缺省打开的⽂件描述符,分别是标准输⼊0,标准输出1,标准错 误2。前面说过,标准输入,输出,错误,这三位是系统默认打开的!!!!因此它们在系统默认打开时,已经有fd了,就已经把0,1,2占据了!!!!

那系统调用open的上一层语言层面的接口fopen的返回值怎么又是FILE*类型的呢?这里的FILE又是个什么玩意?

答案是在语言层面的FILE是一个typedef出来的结构体 !!但在OS层面,只认fd,不认FILE。既然不认,我语言层面又只有FILE,但语言层面的接口的执行又要去调用系统调用接口,那这该咋办呢?答案是FILE里一定封装了fd!!!!

②.内容角度

那上面这些个fd数字(0,1,2,3,4)到底有啥含义呢?答案是它们是数组下标 !那这个数组是用来干啥的呢?上面有个结论,打开文件的本质是进程打开文件,属于操作系统的范畴。操作系统需要把打开的文件管理起来,管理方式是先描述,再组织。

当进程打开文件时,内核会创建一个struct file,上面的成员(包括内容+属性)与磁盘上的文件是相对应的。打开多个文件,就会创建多个对应的struct file。创建struct file,就是先描述。所以再组织,就是将各个文件对应的struct file链接起来!所以OS对被打开文件的管理,就是对链表的增删查改!

每个struct file都有一段缓冲区,磁盘上对应文件的内容就会被加载到这个缓冲区上。

所以打开(open)这个过程,其实是创建struct file,然后把文件的内容+属性加载到对应的struct file上,而执行读/写一类的操作,就是从缓冲区里进行读写。

那怎么分清哪些struct file是某一个对应进程创建的呢?

当一个进程被创建,在进程的PCB里还会创建一个叫struct file_struct 的文件描述符表。而这个表里会包含一个struct file*类型指针数组fd_arry\[\]。每个元素指向一个file_struct,那么这些元素的下标就是上面的fd!!

而属于系统调用的read函数的底层是,去文件描述符表里索引,找到对应的struct file,然后将其文件缓冲区的内容拷贝一份,拷贝到用户层的缓冲区里,所以read的本质是内核到用户空间的拷贝函数!

**对文件的任何操作,都必须先把文件加载到内核的struct file的缓冲区里!**假如要修改文件内容,就先将文件内容加载到缓冲区内,然后对缓冲区上的内容进行修改,修改完成后,将缓冲区内容写回磁盘。

那加载的本质又是什么呢?答案是从磁盘到内存的拷贝!

4.重定向的原理

①.fd分配原则

首先我们要明晰fd的分配原则:当新的文件被加载进内存(被进程打开),OS就会去到文件描述符表里去查询,将查到的最小的,且没有被使用的空间的下标,作为新的fd给用户。

②.说回重定向

下面代码演示了很有意思的一幕:

先将fd = 1的输出流stdout关闭了,然后同时打开一个log.txt文件,并打印log,txt的fd到屏幕上。这时我们发现fd并没有打印到屏幕上,而是写入了log,txt里,这是什么鬼?

哈哈,这就是出现了重定向!

我们来说说原理:

补充一点:printf的底层是向stdout指向的屏幕文件写入,而std只认fd = 1,也就是说下标fd = 1的元素是屏幕文件,才能向屏幕文件写入东西!

所以重定向的本质是是去修改files_struct里指定下标所对应元素(指针)的指向。也就是用新文件的struct file的地址去覆盖旧的地址。

这里还有个系统调用------dup2,可以用来重定向:

用newfd对应的地址去覆盖oldfd对应的地址。使得oldfd的地址指向新文件的 struct file。也就是说oldfd对应的指针,最终是newfd对应指针的一份拷贝!

所以形参要传newfd和oldfd:

重定向 = 打开文件的方式 + dup2。

最后再来说一个点,上面fd = 1的指针经重定向指向新的 struct file,那么原来的 struct file该怎么解决呢?会不会造成空间无法释放,进而造成浪费呢?

答案是struct file上有个计数器ref_cnt。同时由于一个文件支持多个进程打开,也就是说这些进程的files_struct上都会有指针指向这个struct file,每多一个指针指向,ref_cnt就++一次,相反每少一个指针指向,ref_cnt就--一次,当ref_cnt = 0的时候,OS会将这个struct file释放掉。

相关推荐
码不停蹄Zzz1 小时前
linux驱动程序入门2
linux
captain3761 小时前
TCP网络编程:ServerSocket与Socket详解
服务器·网络·tcp/ip
ShineWinsu2 小时前
对于MySQL:内置函数的解析
linux·数据库·c++·mysql·面试·函数·查询
万物智能信息科技2 小时前
RK3568 的多路显示移植—【万物智能之开源鸿蒙OpenHarmony系统实战开发系列教程】
linux·开发语言·华为·开源·harmonyos
IT菜鸟程2 小时前
Ubuntu 下 apt 版 Nginx 升级为源码编译版本完整操作指南(1.24.0 → 1.30.4 实战)
linux·nginx·ubuntu
新时代牛马2 小时前
Linux 磁盘管理:分区、文件系统、挂载与扩容
linux·运维·服务器
weixin_402486343 小时前
VS Code Codex/Claude Extension 无法安装 / 无法正常打开
linux·服务器·vscode
大树883 小时前
液冷系统的真正瓶颈,藏在那层不到1毫米的材料里
大数据·运维·服务器·人工智能·ai
深念Y3 小时前
iOS模拟器在无Metal的NVIDIA显卡环境下的可行性研究报告
服务器·ios·unix·pve·freebsd