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

发布时间:2026/9/12 19:58:18
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打开⽂件的⽅式不仅仅是fopenifstream等流式语⾔层的⽅案其实系统才是打开⽂件最底层的⽅ 案。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的缓冲区里假如要修改文件内容就先将文件内容加载到缓冲区内然后对缓冲区上的内容进行修改修改完成后将缓冲区内容写回磁盘。那加载的本质又是什么呢答案是从磁盘到内存的拷贝3.重定向的原理①.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释放掉。四.理解一切皆文件在linux包括硬件设备也是抽象的文件每种硬件设备在驱动层都具有一套自己的读写方法而且不同设备读写方法完全不同。之前说过OS对硬件管理是先描述再组织将硬件设备生成对应的结构体并将不同的硬件的结构体链接起来。想要对某个设备执行写/读操作时会通过以下的调用链注意先将设备打开加载到内存上形成对应的struct file。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询