Linux最全【Linux】基础IO ——中(1),原理+实战讲解

最全的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<fcntl.h>
#include<unistd.h>

int main()
{
//c call
printf(“hello printf\n”);
fprintf(stdout, “hello fprintf\n”);
fputs(“hello fputs\n”, stdout);
//system call
const char* byh = “hello write\n”;
write(1, byh, strlen(byh));

fork();

return 0;                          

}


**注意观察,当我们重定向之后,为什么除了write以外都打印了两次呢?**  
 ![请添加图片描述](https://img-blog.csdnimg.cn/45b93066e79a42788aa36851cc53974b.png)


我们发现往显示器上输出的结果是合理的,但是往普通文件上输出的结果却很诡异,它输出了 7 条信息,且使用 C 语言接口的都输出了两次,使用系统调用接口的输出了一次。


我们就能理解重定向后,刷新策略由行刷新变为全缓冲,也就是说 fork 时,数据还在 C 缓冲区中,所以重定向后,C 接口的数据输出了两份;而向显示器输出时,因为显示器的刷新策略是行刷新,且这里的每条数据都有 \n,所以每执行完 printf,数据就立马刷新出来,最后 fork 时便无意义了。


而重定向后,系统接口没有受影响的原因是 write 会绕过语言层缓冲区,写到内核层缓冲区,而其实只要是数据都要写时拷贝,但大部分情况只针对用户数据,对于内核数据,数据属于操作系统不会写时拷贝,属于进程会写时拷贝,但这种情况很少考虑,现在我们就认为写时拷贝主要拷贝的是用户数据。


通常我们不建议所语言接口和系统接口混合使用,因为可能会出现一些难以理解的现象。




---


## 💨 2. dup2


* 输出重定向



#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>

//输出重定向
int main()
{
int fd = open(“log.txt”, O_WRONLY|O_CREAT, 0644);
if(fd < 0)
{
perror(“open”);
return 1;
}

dup2(fd, 1);//此时再写入就不是标准输出,而是fd 
const char\* msg = "hello dup2->output\n";
int i = 0;
while(i < 5)
{
    write(1, msg, strlen(msg));
    i++;
}

close(fd);

return 0;

}


![请添加图片描述](https://img-blog.csdnimg.cn/4843a690b7b841649ee303f156eb7e33.png)


* 输入重定向



#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>

//输入重定向
int main02()
{
int fd = open(“log.txt”, O_RDONLY);
if(fd < 0)
{
perror(“open”);
return 1;
}

dup2(fd, 0);//此时再读就不是从标准输入读,而是fd
char buffer[1024];
ssize\_t sz = read(0, buffer, sizeof(buffer) - 1);
if(sz > 0)                                       
{
    buffer[sz] = 0;
    printf("%s", buffer);
}

close(fd);

return 0;

}


![请添加图片描述](https://img-blog.csdnimg.cn/c056ca5fd51f4a70958404d90222afa3.png)


* 追加重定向



#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>

//追加重定向
int main03()
{
int fd = open(“log.txt”, O_WRONLY|O_APPEND);
if(fd < 0)
{
perror(“open”);
return 1;
}

dup2(fd, 1);//此时再写入就不是标准输出,而是fd
const char\* msg = "hello dup2->append\n";
int i = 0;
while(i < 5)
{
    write(1, msg, strlen(msg));
    i++;
}                                            

close(fd);

return 0;                                    

}


![请添加图片描述](https://img-blog.csdnimg.cn/7f6824f6c485425eb56772a9112bd9b1.png)  
 echo 是一个进程;“hello world” 默认是调用 printf 或 write 往显示器上输出;log.txt 是调用 open 使用 O\_WRONLY|O\_CREAT 打开;> 是调用 dup2,将默认标准输出 1 的内容改为 log.txt;


`<<` 就是 dup2(fd, 0),且 open 文件的方式是 O\_RDONLY;


`>>`同 >,都是 dup2(fd, 1),只不过它打开文件的方式是 O\_WRONLY|O\_APPEND;


将来 fork,创建子进程,子进程会以父进程的大部分数据为模板,子进程进行程序替换时,并不会影响曾经打开的文件,也就不会影响重定向对应的数据结构。




---


## 💨 3. 理解文件系统


上文咱们一直在谈论打开的文件,那如果一个文件没有被打开呢?它静静的躺在磁盘上。那咱们现在就要了解一下磁盘上的文件系统。首先要了解磁盘结构,这有助于咱们形象理解“把数据刷新到磁盘”这种话,而不是一听而过。


### 💦 3.1 了解磁盘结构


![请添加图片描述](https://img-blog.csdnimg.cn/966a410389944591b2beb725121e9eae.png)  
 磁盘是计算机中的一个机械设备。


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


机械硬盘的寻址的工作方式:盘片不断旋转,磁头不断摆动,定位到特定位置。


![请添加图片描述](https://img-blog.csdnimg.cn/f72eae50a7664d58af0cda973f20a543.png)  
 类比磁带,我们可以把磁盘盘片想象成线性结构。


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


![请添加图片描述](https://img-blog.csdnimg.cn/26616dd46aa349589f0e903a3840bd7c.png)




---


### 💦 3.2 inode


为了能解释清楚inode我们先简单了解一下文件系统


![在这里插入图片描述](https://img-blog.csdnimg.cn/da0c3dfa7aef49c6ba160eceeece9254.png)  
 Linux ext2文件系统,上图为磁盘文件系统图(内核内存映像肯定有所不同),磁盘是典型的块设备,硬盘分区被划分为一个个的block。一个block的大小是由格式化的时候确定的,并且不可以更改。例如mke2fs的-b选项可以设定block大小为1024、2048或4096字节。而上图中启动块(Boot Block)的大小是确定的


* Block Group:ext2文件系统会根据分区的大小划分为数个Block Group。而每个Block Group都有着相同的结构组成。政府管理各区的例子
* 超级块(Super Block):存放文件系统本身的结构信息。记录的信息主要有:bolck 和 inode的总量,未使用的block和inode的数量,一个block和inode的大小,最近一次挂载的时间,最近一次写入数据的时间,最近一次检验磁盘的时间等其他文件系统的相关信息。Super Block的信息被破坏,可以说整个文件系统结构就被破坏了
* GDT,Group Descriptor Table:块组描述符,描述块组属性信息,有兴趣的同学可以在了解一下
* 块位图(Block Bitmap):Block Bitmap中记录着Data Block中哪个数据块已经被占用,哪个数据块没有被占用
* inode位图(inode Bitmap):每个bit表示一个inode是否空闲可用。
* i节点表:存放文件属性 如 文件大小,所有者,最近修改时间等
* 数据区:存放文件内容


将属性和数据分开存放的想法看起来很简单,但实际上是如何工作的呢?我们通过touch一个新文件来看看如何工  
 作。



[root@localhost linux]# touch abc
[root@localhost linux]# ls -i abc


为了说明问题,我们将上图简化:


![在这里插入图片描述](https://img-blog.csdnimg.cn/43440b66666d482ba2464f4106c68cc9.png)  
 ![请添加图片描述](https://img-blog.csdnimg.cn/6911af75e7a343f2adafcb71ba9ea9cd.png)


创建一个新文件主要有一下4个操作:


1. 存储属性  
 内核先找到一个空闲的i节点(这里是263466)。内核把文件信息记录到其中。
2. 存储数据  
 该文件需要存储在三个磁盘块,内核找到了三个空闲块:300,500,800。将内核缓冲区的第一块数据  
 复制到300,下一块复制到500,以此类推。
3. 记录分配情况  
 文件内容按顺序300,500,800存放。内核在inode上的磁盘分布区记录了上述块列表。
4. 添加文件名到目录


新的文件名abc。linux如何在当前的目录中记录这个文件?内核将入口(263466,abc)添加到目录文件。文件名和inode之间的对应关系将文件名和文件的内容及属性连接起来。


创建文件:遍历inode Bitmap位图中找0,申请一个未被使用的inode,填入属性信息。并把这个映射关系写到当前目录的Data blocks中。


查看目录:根据目录inode找到与其映射的文件名


向文件写入:遍历block Map找到若干未被使用的块儿,将该文件的inode与这些blocks建立映射关系,再向blocks中写入内容。


查看文件内容:cat hello.c → 查看当前目录lesson15的data Blocks数据块儿 → 找到映射关系:文件名儿对应的inode编号 → 在inode Table中找到inode → 找到对应的blocks[] → 打印文件内容。 查看文件属性类似。


**理解目录**  
 我们知道程序员定位一个文件,是通过绝对路径或相对路径定位的,但不管是绝对路径还是相对路径最终一定是要有一个目录。目录当然是一个文件,也有独立的 inode,也有自己的数据块,目录中的 block 数组能找到对应的数据块,目录的数据块维护的是文件名和 inode 的映射关系。换言之,在目录下创建文件时,除了给文件申请 inode、数据块之外,还要把文件名和申请创建成功之后文件的 inode 编号写到目录的数据块中。所以现在就能理解为什么大多数操作系统下同一个目录中不允许存在同名文件。所以只要我们找到了目录就可以找到文件名,根据映射然后可以找到文件 inode,通过 inode 读取文件的属性,也可以通过 inode 中的数组读取文件的内容。所以 ls -l 时就可以读到文件的属性信息,它是在当前目录对应的 inode 下找到对应数据块中文件名和文件名映射的 inode,再去找对应文件的 inode,此时就看到文件的属性了。


**理解删除文件**


之前我们说过,计算机中删除一个文件并不是真正的删除,而是把那块空间标识为无效,现在理解的是不用把 inode 属性清空,不用把 inode 对应的数据块清空,只要把两个位图中对应的比特位由 1 到 0,再把所在的目录下中的对应的映射关系去掉,此时空间就是无效的,下一次再新建文件时,就可以直接把无效的空间覆盖。


**先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前在阿里**

**深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!**

**因此收集整理了一份《2024年最新Linux运维全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。**
![img](https://img-blog.csdnimg.cn/img_convert/8f66bcc5b95874ae52b3bb0250fee9b1.png)
![img](https://img-blog.csdnimg.cn/img_convert/925a6eaf9c7e5e7762834ddd3b1e8253.png)
![img](https://img-blog.csdnimg.cn/img_convert/92b1686b8fd4f233d2fb28d259fc9019.png)
![img](https://img-blog.csdnimg.cn/img_convert/a0b02e8c87b35bfc3cc4dca42bbac1ce.png)
![img](https://img-blog.csdnimg.cn/img_convert/d9082b7cb7e4194bff8cc18a6822b7ec.png)

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上运维知识点,真正体系化!**

**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**

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

[外链图片转存中...(img-qUZSW3YP-1715326496059)]
[外链图片转存中...(img-RHduvTcE-1715326496059)]
[外链图片转存中...(img-okTOJy5X-1715326496059)]

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上运维知识点,真正体系化!**

**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**

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

  • 14
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值