Linux_系统文件IO详解

Linux_系统文件I/O详解

系统文件I/O

在学习c语言阶段时,我们就已经学习过了对文件的操作,但大多数同学的c文件的操作,并不理解,甚至说压根就不明白文件操作的底层含义,如果学习文件操作还只是停留在语言层面上,是很难对文件有一个比较深刻的了解!

我们知道C程序会默认打开三个输入输出流:stdin,stdout,stderr,它们分别代表键盘,显示器,显示器.

在这里插入图片描述

文件的相关操作最终一定是访问计算机的硬件:显示器,键盘,文件(磁盘),而OS又是硬件的管理者,由此我们得知,所有语言上对"文件"的操作,都必须贯穿OS!
在这里插入图片描述

系统调用接口

1.open:

在这里插入图片描述

pathname: 要打开或创建的目标文件
flags: 打开文件时,可以传入多个参数选项,用下面的一个或者多个常量进行“或”运算,构成flags。
参数:
 O_RDONLY: 只读打开
 O_WRONLY: 只写打开
 O_RDWR : 读,写打开
 		这三个常量,必须指定一个且只能指定一个
 O_CREAT : 若文件不存在,则创建它。需要使用mode选项,来指明新文件的访问权限
 O_APPEND: 追加写
  
 返回值:
 成功:新打开的文件描述符(下文会详解)
 失败:-1

PS: mode是用来设置,用户权限的,可自行设置用户,组和其它对文件的权限,如果不写的话,文件被创建出时,其权限是随机的,所以一般情况下用户需要填入三者的权限


  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<unistd.h>
  4 #include<fcntl.h>
  5 #include<sys/types.h>
  6 #include<sys/stat.h>
  7 int main()
  8 {
  9   int fd =open("./log.txt",O_WRONLY|O_CREAT,0644);
 10   if(fd<0)
 11   {
 12     perror("OPEN FILED\n");
 13     return 1;
 14   }
 15   const char* msg="Hello File\n";                                                                                            
 16   write(fd,msg,strlen(msg));
 17   close(fd);
 18 
 19 
 20   return 0;
 21 }

在这里插入图片描述

文件描述符fd

在上文我们用到open函数时,看到open的返回值是int类型的整数,但是其具体有什么含义呢?

  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<unistd.h>
  4 #include<fcntl.h>
  5 #include<sys/types.h>
  6 #include<sys/stat.h>
  7 int main()
  8 {
  9   int fd1 = open("./log1.txt",O_WRONLY|O_CREAT,0644);
 10   int fd2 = open("./log2.txt",O_WRONLY|O_CREAT,0644);
 11   int fd3 = open("./log3.txt",O_WRONLY|O_CREAT,0644);
 12   int fd4 = open("./log4.txt",O_WRONLY|O_CREAT,0644);
 13   int fd5 = open("./log5.txt",O_WRONLY|O_CREAT,0644);
 14   int fd6 = open("./log6.txt",O_WRONLY|O_CREAT,0644);
 15   int fd7 = open("./log7.txt",O_WRONLY|O_CREAT,0644);
 16   printf("%d\n",fd1);
 17   printf("%d\n",fd2);
 18   printf("%d\n",fd3);
 19   printf("%d\n",fd4);                                                                                                        
 20   printf("%d\n",fd5);
 21   printf("%d\n",fd6);
 22   printf("%d\n",fd7);
 23   return 0;
 24 }

在这里插入图片描述

此时我们发现当我们创建多个文件时,返回的fd值是从3开始顺序增加的,我们稍加思考一下会发现这与我们在c语言学习过的数组的下标是一样的.

在这里插入图片描述

在这里插入图片描述

	文件描述符fd就是从0开始的整数,当我们打开文件时,操作系统在内存中要创建相应的数据结构来描述文件.于是有了file结构体,表示一个打开的文件对象.而进程执行open系统调用时,必须要让进程和文件关联起来,所以每个进程内部都有一个指针*files,指向一张表files_struct,该表最重要的一部分就是包含一个指针数组,每个元素都指向打开文件的指针!所以本质上文件描述符就是数组的下标也就是说拿到文件描述符,就能找到对应的文件

文件描述符fd的分配规则:

文件描述符的分配规则:在files_struct数组当中,找到当前没有被使用的最小的一个下标,作为新的文件描述符。

重定向

每个文件描述符都是一个内核中文件描述信息数组的下标,对应有一个文件的描述信息用于操作文件,而重定向就是在不改变所操作的文件描述符的情况下,通过改变描述符对应的文件描述信息进而实现改变所操作的文件

  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<unistd.h>
  4 #include<fcntl.h>
  5 #include<sys/types.h>
  6 #include<sys/stat.h>
  7 int main()
  8 {
  9   close(1);
 10   int fd = open("./log1.txt",O_WRONLY|O_CREAT,0644);
 11   printf("%d\n",fd);
 12   printf("hello world\n");
 13   printf("hello world\n");
 14   printf("hello world\n");
 15   printf("hello world\n");
 16   printf("hello world\n");
 17   printf("hello world\n");                                                                                                   
 18   return 0;
 19 }

在这里插入图片描述

运行后我们发现,明明我们在代码里写了打印语句,但是显示器上却没有显示?

在这里插入图片描述

此时我们看到明明应该打印在显示器里的语句,全部被输入到了log1.txt文件中,而且文件描述符fd也变成了1,这种现象就叫做重定向

那么重定向的本质是什么?

在上文中我们说过文件描述符的分配规则是在files_struct数组当中,找到当前没有被使用的最小的一个下标,作为新的文件描述符。当我们close(1)时,1号文件已经被关闭了,那么最小的没用被使用的下标就是1.

在这里插入图片描述

dup2 系统调用

在这里插入图片描述

int dup2(int oldfd, int newfd);
函数功能为将newfd描述符重定向到oldfd描述符,相当于重定向完毕后都是操作oldfd所操作的文件
但是在过程中如果newfd本身已经有对应打开的文件信息,则会先关闭文件后再重定向(否则会资源泄露)
  1 #include<stdio.h>  
  2 #include<string.h>  
  3 #include<unistd.h>  
  4 #include<fcntl.h>  
  5 #include<sys/types.h>  
  6 #include<sys/stat.h>  
  7 int main()  
  8 {  
  9   int fd = open("./log1.txt",O_WRONLY|O_CREAT,0644);  
 10   dup2(fd,1);  
 11   printf("%d\n",fd);  
 12   printf("hello dup2\n");
 13   printf("hello dup2\n");
 14   printf("hello dup2\n");
 15   printf("hello dup2\n");
 16   printf("hello dup2\n");
 17   printf("hello dup2\n");                                                                                                    
 18   return 0;
 19 }        

在这里插入图片描述

缓冲区及刷新策略

我们先来看一段之前写的代码

  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<unistd.h>
  4 #include<fcntl.h>
  5 #include<sys/types.h>
  6 #include<sys/stat.h>
  7 int main()
  8 {
  9   close(1);
 10   int fd = open("./log1.txt",O_WRONLY|O_CREAT,0644);
 11   const char* msg="hello File\n";                                                   
 12   write(fd,msg,strlen(msg));
 13   printf("%d\n",fd);
 14   printf("hello dup2\n");
 15   printf("hello dup2\n");
 16   printf("hello dup2\n");
 17   printf("hello dup2\n");
 18   printf("hello dup2\n");
 19   return 0;
 20 }  

在这里插入图片描述

依旧是重定向到log1.txt文件中

但是我们发现代码写的有点问题,我们既然打开了文件,但是最后程序退出前我们并没有关闭,当我们加入close(fd)关闭文件时

在这里插入图片描述

log1.txt里的内容就只剩下了一行,这是什么原因?

在这里插入图片描述

用户->OS:
刷新策略:
1.立即刷新(不缓冲)
2.行刷新(行缓冲'\n'),比如,显示器打印
3缓冲区满了,才刷新(全缓冲),比如,磁盘往文件里写入

现在就可以回答为什么log.txt里只有一行,因为,当我们close(fd)时文件被关闭,而此时printf打印的语句全部都存在c缓冲区中,而想要将c缓冲区里的内容刷新到OS缓冲区需要系统调用接口,而此时fd已经被我们关闭了,压根就找不到文件,而write本身就是系统调用接口,它会直接刷新到OS缓冲区,所以不受影响

理解文件系统

我们知道电脑上的硬盘空间是非常大的,目前正常的电脑一般都有512GB,这对操作系统而言,管理这么大的空间是成本非常高的,然而操作系统为了方便管理硬盘空间,会将硬盘进行分区管理,所谓文件系统就是操作系统管理硬盘的一种软件分层方式

在这里插入图片描述

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节点表:存放文件属性 如 文件大小,所有者,最近修改时间等
    
数据区:存放文件内容

inode

在Linux中inode是一个结构体,其中包含了

  • inode 编号
  • 用来识别文件类型,以及用于 stat C 函数的模式信息
  • 文件的链接数目
  • 属主的ID (UID)
  • 属主的组 ID (GID)
  • 文件的大小
  • 文件所使用的磁盘块的实际数目
  • 最近一次修改的时间
  • 最近一次访问的时间
  • 最近一次更改的时间

在这里插入图片描述

inode编号

操作系统在查找文件的时候,是不会通过文件名来判断该文件是否为要找的文件,而是通过inode编号找到文件inode信息,通过inode信息找到对应的数据块

在这里插入图片描述

理解软硬链接

软连接:就是给文件创建一个快捷方式

在这里插入图片描述

硬链接:本质不是一个独立的文件,而是一个文件名和inode编号的映射关系,因为自己没有独立的inode编号

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值