【Linux】基础IO —— 深入理解文件系统 软硬链接_linux基础io深入理解文件系统

最全的Linux教程,Linux从入门到精通

======================

  1. linux从入门到精通(第2版)

  2. Linux系统移植

  3. Linux驱动开发入门与实战

  4. LINUX 系统移植 第2版

  5. Linux开源网络全栈详解 从DPDK到OpenFlow

华为18级工程师呕心沥血撰写3000页Linux学习笔记教程

第一份《Linux从入门到精通》466页

====================

内容简介

====

本书是获得了很多读者好评的Linux经典畅销书**《Linux从入门到精通》的第2版**。本书第1版出版后曾经多次印刷,并被51CTO读书频道评为“最受读者喜爱的原创IT技术图书奖”。本书第﹖版以最新的Ubuntu 12.04为版本,循序渐进地向读者介绍了Linux 的基础应用、系统管理、网络应用、娱乐和办公、程序开发、服务器配置、系统安全等。本书附带1张光盘,内容为本书配套多媒体教学视频。另外,本书还为读者提供了大量的Linux学习资料和Ubuntu安装镜像文件,供读者免费下载。

华为18级工程师呕心沥血撰写3000页Linux学习笔记教程

本书适合广大Linux初中级用户、开源软件爱好者和大专院校的学生阅读,同时也非常适合准备从事Linux平台开发的各类人员。

需要《Linux入门到精通》、《linux系统移植》、《Linux驱动开发入门实战》、《Linux开源网络全栈》电子书籍及教程的工程师朋友们劳烦您转发+评论

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以点击这里获取!

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>

int main()
{
//stdout -> 1
printf(“hello printf 1\n”);
fprintf(stdout, “hello fprintf 1\n”);

// stderr -> 2
perror("hello perror 2"); //stderr

const char \*s1 = "hello write 1\n";
write(1, s1, strlen(s1));

const char \*s2 = "hello write 2\n";
write(1, s2, strlen(s1));

//cout -> 1
std::cout << "hello cout 1" << std::endl;
//cout -> 2
std::cerr << "hello cerr 2" << std::endl;

return 0;

}


结果如下~


![在这里插入图片描述](https://img-blog.csdnimg.cn/b0f37d07f79d4c80a628b68d04b652bf.png)


* 我们发现,**重定向只对1号文件描述符有用**;也就是正确信息被重定向
* 文件描述符 1 和 2 对应的都是显示器文件,但是题目两个是不同的,如同认为同一个显示器文件,被打开了两次


![在这里插入图片描述](https://img-blog.csdnimg.cn/ed878a2410bd4130af24518257eba291.png)



> 
> 一般而言,如果程序运行有可能**有问题**的话,建议使用`stderr`,或者`cerr`来打印  
>  如果是常规的文本内容,我们建议进行cout 或 stdout 进行打印
> 
> 
> 


💦举例:常规信息和报错信息**分开打印**  
 正确的打印到ok.txt ,错误的打印到err.txt 也称错误重定向



./myfile 1 > log.txt 2 > err.txt


![在这里插入图片描述](https://img-blog.csdnimg.cn/2a23b4b8598d4073829ce0604c6e13a0.png)


💦但如果我们像都打印在一个文件中呢?



./myfile > log.txt 2>&1


💢先重定向,指向log.txt;把1的内容给2拷贝一份,最后1和2指向同一个文件


![在这里插入图片描述](https://img-blog.csdnimg.cn/6ce4b37fd52c431d8da7c16509e966a2.png)结果还真的是  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/78771475707f4c38a18bb24ab6d7cd8e.png)  
 还有一个骚操作也可以实现



cat < log.txt > back.txt//相当于拷贝


我们一个都见过这个`errno`(**错误码**)的吧



#include <errno.h>

RETURN VALUE
open() and creat() return the new file descriptor, or -1 if an error occurred (in which
case, errno is set appropriately).


如果打开成功,返回文件描述符,打开失败,errno被设置,所以**perror会根据全局的错误码输出对应的错误原因**


如果我们自己想设计一个perror



void myperror(const char *msg)
{
fprintf(stderr, “%s: %s\n”, msg, strerror(errno));
}


此前已经删除了log.txt  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/b610bd21b4f9457e842cbe66df306e89.png)


### 二 . 理解文件系统


#### 🎨科普背景知识


🥑有没有没有被打开的文件呢? 在哪里呢?


* 当然存在,在磁盘上


🥑我们学习磁盘级别的文件,我们的侧重点在哪?


1. 单个文件角度 —— 这个文件在哪里?这个文件多大?这个文件的其他属性是什么?
2. 站在系统角度 ——一共有多少个文件?各自属性在哪里?如何快速找到?还可以存储多少个文件


接下来我们来正式了解一下磁盘吧


1. 内存 - 掉电易失存储介质
2. 磁盘 - 永久性存储介质 还有: SSD(**固态 贵!**) 、U盘、flash卡、光盘、磁带


#### 🎨了解磁盘结构


##### 🔵物理结构


**磁盘**是一个**外设** 且是我们计算机中唯一的一个**机械设备**(相对而言很慢)


这个磁盘的盘片就像光盘一样,数据就在盘片上放着,只不过光盘是只读的,磁盘是可读可写的


光说有点抽象的,直接上图


![在这里插入图片描述](https://img-blog.csdnimg.cn/54bd6c37fbdd4e52be0bb0bab95f40e0.png)


盘面上要存储数据!(二进制) -> 但计算机只认识二进制 -> **二进制是两态** —> 我们想到磁铁也是两态的


* 向**磁盘写入**本质就是**改变磁盘的正负性**(磁头)


##### 🟡磁盘的存储结构


机械硬盘的寻址的工作方式:盘片不断旋转,磁头不断摆动,定位到特定的扇区(面 — 磁道 — 扇区)  
 通过柱面Cylinder —— 磁头Head —— 扇区Sector 的寻址方法为`CHS寻址`


扇区的大小:`512字节`是硬件上的要求(外磁道和内磁道都是一样大小,密度不一样)


![在这里插入图片描述](https://img-blog.csdnimg.cn/d9844250e3644948ac8f6a165d98174b.png)


##### 🟢磁盘的虚拟结构


类比磁带,我们可以把磁盘盘片想象成线性结构。


站在OS角度,我们就认为磁盘是线性结构,要访问某一扇区,就要**定位数组下标**`LBA`(logic block address);要写到物理磁盘上,就要把LBA地址转化成磁盘的三维地址(磁头,磁道,扇区)。这种关系类似于我们之前的虚拟地址空间和物理内存


![在这里插入图片描述](https://img-blog.csdnimg.cn/9be6b0a2baa94a22bfb8ed2dde744786.png)


所以:找到特定扇区的位置 ——> 找到数组特定的位置;对磁盘的管理——> 对数组的管理


#### 🎨文件系统与inode


文件在磁盘上是如何被保存的?文件是在磁盘中的,而磁盘现在被我们想象成一个线性结构。


💜 磁盘空间很大,管理成本高。我们采用**分治思维**,类比管理我们的国家,我们分成好几个省份,再分成好几个市,最后轮到区。因此我们就对大磁盘 ——


1️⃣ 分区:大磁盘 → 小空间,化整为零


​ 2️⃣ 格式化:给每个分区写入文件系统


所以理论上,我能把这100G的小空间管理好,其他空间就复刻我就好啦,因为硬件都是标品,当然了不同分区也可以写入不同的文件系统


![在这里插入图片描述](https://img-blog.csdnimg.cn/56f333d47df44c7dae42dcdb41d816a9.png)


* boot block 存在于每个分区的开头,备份文件,是与启动相关的,供启动时查找分区
* 我们再把剩下的空间继续拆解分组,Block group 0 ,Block group 1 … 那么问题就又变成了如果我能管理好Block Group 0,就能管好1~n这些,因此研究文件系统又缩小范围了,就变成研究这一个Block Group 0


话不多说开始吧


虽然磁盘的基本单位是扇区(512字节),但是**操作系统**(文件系统)和磁盘进行IO的基本单位是`4KB`(8\*512字节),`4KB`是`block`大小,所以磁盘被称为**块设备**


哪怕我们只想在磁盘上读取1字节,OS也必须直接读取4KB的数据  
 原因有两个:


1. 512字节太小了,有可能导致多次IO,进而导致效率的降低
2. **解耦合**:如果操作系统使用和磁盘一样的大小,万一磁盘基本大小改变了,OS的源代码也要不要跟着改呢?硬件(磁盘)和软件(OS)进行解耦




---

 逐个解释: 
2. `Super Block`:文件系统的属性信息,**整个分区属性的属性集**(每个块组都有 防止磁盘被刮伤而找不到 文件属性)
3. `Data blocks`:多个4KB(扇区\*8)大小的集合,**保存**的都是特定文件的**内容**
4. `inode Table`:inode是一个大小为128字节的空间,保存的是对应文件的属性,该块组内,**所有文件的inode空间的集合**,需要标识唯一性,每一个inode块都要有一个inode编号!(一般而言,一个文件,一个inode,一个inode编号)
5. `BlockBitmap`(位图):**统计`block`的使用情况**。假设有10000+个blocks,就有一一对应的比特位。其中比特位为1,代表该block被占用,否则表示可用
6. `inode Bitmap`:**统计`inode`的使用情况**,假设有10000+个inode,就有一一对应的比特位。其中比特位为1,代表该inode被占用,否则表示可用
7. `GDT`:**块组描述符**,已经使用了多少,有多少个inode,已经被占用了多少个,还剩下多少个,使用了多少


💥众所周知,文件 = 文件内容 + 文件属性,其中文件**内容**放在`Data blocks`中,**属性**放在`inode Table`中


inode内部保存了一个数组,保存了对应块的编号,二者关系就联系起来了  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/9fddc3703f6d4b5c82016bf7b4623d20.png)Linux中真正标识一个文件,是通过文件的`inode`**编号**,一个文件,一个inode(属性集合);一个inode也都有自己的编号。


那么要创建文件就要在`inode Table`中**申请**一个未被使用的inode,**填入属性**;文件中还有内容,inode还用数组存储了相关联的blocks块编号,我们可以简单地理解成 ——



struct inode{
//文件的大小
//文件的inode编号
//其他属性
int block[15];
}


⚡万一这个文件特别大呢? 怎么办?



> 
> 不是所有的`data block` 只能存文件数据,**也可以存其他块的块号**  
>  如果文件特别大,最后的block存的是其他block的块号,所以最后指向的是更多的block来存储
> 
> 
> 


![在这里插入图片描述](https://img-blog.csdnimg.cn/d660dd2014f446548004972cf52a4fdb.png)


我们知道要找到文件:inode编号 —— 分区特定的block group —— inode —— 属性 —— 文件



> 
> 🎨可是我们怎么知道inode呢?(Linux中,inode属性里面,没有文件名这样的说法)
> 
> 
> 


预备知识:


* 一个目录下,是不是可以保存很多文件,但这些文件没有重复的文件名!
* **目录也算是文件**,有自己的`inode`(存的是目录的大小、权限、(链接数)、拥有者、所属组等)、有自己的`data block`(存的是**文件名和inode的映射关系**),**因为文件名不存在于文件的inode里面**


![在这里插入图片描述](https://img-blog.csdnimg.cn/8314b96010bf4a6f9f25289931350f2c.png)


回答上面的问题:我们是**依托目录文件**来找到inode编号,因为目录的`data block`中保存了**inode编号和文件名的映射关系**,所以能找到文件名进而找到inode编号




---


**💢灵魂多问:**


* **目录下创建文件**:遍历`inode Bitmap`,位图中找0,申请一个未被使用的inode,随后便置1;向inode table中填入属性信息(权限、ACM时间)。并把这个**映射关系**(文件名是用户输入,inode是我们从文件系统申请得到的)**写到当前目录的Data blocks中**。


![在这里插入图片描述](https://img-blog.csdnimg.cn/89db2bf9ef7942a5873117c586c5bef2.png)


* **查看文件**,根据目录inode找到与其映射的文件名 以及属性 全部打印
* **向文件写入**:遍历block Map**找到若干未被使用的块儿**,将该文件的inode与这些blocks**建立映射**关系,再向blocks中写入内容。


![在这里插入图片描述](https://img-blog.csdnimg.cn/7b14fb17a9664d7a8b7670c147cdcf60.png)


* **查看文件内容**:`cat hello.c` → 查看当前目录的data Blocks数据块儿 → 找到映射关系:文件名儿对应的inode编号 → 在inode Table中找到inode → 找到对应的blocks[] → 文件内容加在进内存中,在刷新到显示屏。
* **删除文件** :在目录的data block,用户提供的文件名,以文件名作为**key值**索引对应的`inode`,在`inode Bitmap`中把**对应的比特位置中由1置0**;再根据属性把使用的数据块儿们也在**Bitmap中把它由1置0**。最后在目录的data block中,删除inode和文件名的映射关系。
* 所以拷贝一个文件需要一会儿,但是删除很快(**因为不需要改文件的属性inode Table和数据data Blocks**,标志文件无效即可,并不用覆盖)


( 如果你在Linux系统中,不小心rm -rf误删了文件,**还能恢复!**(前提是inode未被使用,inode和data block没有被占用)**最好的做法就是什么也不做**!找到你在windows下删除文件到回收站,其实只不过是转移了目录,在回收站中删掉才是相当于1置0了)




---


还有一个问题:位图一开始是不是要被操作系统全清0,那个区域要被分成inode table和super在什么位置 ?GDT是谁写的?inode table的128kb是谁划分的?


* 以上所有的信息都是:**格式化** 也就是**写入文件系统**(写入属性)


**【面试题】:**  
 **🥗系统里还有空间,为什么创建文件老是失败:**


* 因为inode是固定的,data block也是固定的。可能存在 inode还有,data block不够了;inode没有,data block还有的情况(特别少)


说了一大圈,最终为了引出我们的大boss


### 三 . 软硬链接


#### 🌏软链接



**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以点击这里获取!](https://bbs.csdn.net/topics/618542503)**

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

  • 13
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值