LINUX--基础IO

发布时间:2024年01月08日

今天是2024年1月2日,祝大家新年快乐,万事胜意!offer多多,欢乐多多!

目录

什么是IO?

先来看C语言为我们提供了哪些手段(函数接口)

fopen--打开文件

fwrite--对文件进行写入

fread--读取文件内容

fclose--关闭文件

操作实例:对一个文件进行写入

操作实例,对一个文件进行读取

接下来再看看LINUX提供的系统调用接口

open--打开文件

write--对文件进行写入

read--读取文件

close--关闭文件

操作实例,对一个文件进行写入

操作实例,读取一个文件的内容

文件描述符--fd(file descriptor)

文件描述符分配规则

利用fd完成文件重定向

如何实现文件重定向:以输出重定向为例

追加重定向:

输入重定向:

FILE与fd

什么是FILE

C缓冲区与内核缓冲区

什么是缓冲区?

有哪些缓冲区?

这两个缓冲区之间的关系?

如何维护C缓冲区?

谈谈刷新时机

文件系统

所以磁盘是什么呢?

如何对存储在磁盘上的文件进行定位

如何看待磁盘呢?

何为inode?

为什么要有inode编号?

inode编号的作用?

如何删除一个文件?

如何新建一个文件?

软/硬链接

什么是软链接:

如何使用软链接:

什么是硬链接:

如何使用硬链接:


什么是IO?

I input;O output 以我目前的理解,我认为IO就是“写进去”与“拿出来”的过程。

比如说文件IO,就是把内容写进文件里面,得到文件里的内容的过程。

那么,往文件内容写东西,得到文件内容,有哪些“手段”呢?

先来看C语言为我们提供了哪些手段(函数接口)

fopen--打开文件

函数原型:

参数1:filename 可以使用绝对路径和相对路径(什么是绝对路径和相对路径?)

参数2:mode 以哪种方式打开文件

具体有以下几种打开方式

fwrite--对文件进行写入

参数原型:

参数1:ptr 指向任意数据类型的指针,他所指向的内容将写入stream中去

参数2:size,ptr指向数据类型的大小

参数3:count? 写多少个size大小的元素到stream中去

参数4:stream FILE*类型的指针(FILE其实是一个结构体类型)

fread--读取文件内容

函数原型:

参数与fwrite类似,只是将stream里的文件内容写到ptr中

fclose--关闭文件

参数 stream要关闭的文件名

操作实例:对一个文件进行写入

可以看到,内容已经被写入到test.txt中去了

操作实例,对一个文件进行读取

运行结果:

成功读取到了test.txt中的内容


接下来再看看LINUX提供的系统调用接口

在此之前,先说明一下LINUX提供的系统接口与C语言提供的接口之间的关系,简单说就是,C语言提供的接口是对系统接口的的封装,即C接口的底层是使用系统接口实现的

open--打开文件

函数原型:

参数1 pathname 文件名(相对路径/绝对路径)

参数2 flags 以哪种方式打开文件(O_WRONLY(只读),O_CREAT(不存在则创建文件)O_TRUNC(每次打开文件时清空文件)等等)

参数3 mode 设置文件权限

返回值:返回一个文件描述符(fd),它是非负的整数,被用于read、write等系统调用。成功返回的文件描述符会是最小的、当前没有为该进程所打开的文件描述符

write--对文件进行写入

函数原型:

参数1 fd? 文件描述符

参数2 buf? 一个指向任意数据类型的指针,其指向内容将被写到文件中去

参数3 count? 写count个字节到文件中去

返回值:成功返回写入的字节个数,失败返回-1.

read--读取文件

函数原型:

将fd所在文件中至多count个字节存储到buf指针所指向空间中去

参数与write一致

返回值:成功返回成功读到的字节个数,失败返回-1

close--关闭文件

函数原型

使文件描述符不再指代一个文件

返回值:成功返回0 失败返回-1

操作实例,对一个文件进行写入

运行结果:log1.txt中成功写入了msg的内容

操作实例,读取一个文件的内容

运行结果:文件内容成功存入rdmsg中


文件描述符--fd(file descriptor)

是谁打开了文件?是进程。为了让进程知道哪些文件属于自己,所以要建立进程与文件之间的关系,因此在PCB中会存在一个指向files_struct的结构体类型指针,该结构体存有一个

struct files* fd array[32]的数组,数组元素是指向文件的指针,而fd就是这些数组的下标。

可以说,文件描述符是用户使用文件的媒介。

值得注意的是,当一个进程启动时,OS会自动为它打开0、1、2下标所对应的IO流,他们分别是标准输入流、标准输出流、标准错误流。也就是进程不用打开这三个文件,也可以向他们进行写入/读取。

文件描述符分配规则

优先分配进程最近的,未被使用的数组下标作为文件描述符。

验证:

运行结果:

fd的返回值是3,符合预期,因为0 1 2下标已经分配给了键盘、显示器、显示器文件

利用fd完成文件重定向

什么是文件重定向:更改struct files* fd array[32]数组元素的指向。

如何实现文件重定向:以输出重定向为例

运行结果:

分析:close(1)的作用是取消进程与显示器文件的联系,可以理解fd_array[1]不再指向显示器文件,随后我们又创建了log.txt文件,根据文件描述符分配规则,fd_array[1]指向了log.txt,因此当我们再向1号下标所指代的文件中写入,直接写入log.txt而不是显示器文件

追加重定向:

每次进行写入时文件偏移量都位于文件的末尾

输入重定向:

将写入键盘文件的数据写入到log.txt中


FILE与fd

在前面的接口中,有C提供的,例如fopen,fwrite等,返回值是FILE*,也有LINUX提供的系统调用接口,例如open,write等,返回值是fd。C提供的接口其实是对系统调用接口的封装(例如fopen底层一定封装了open),方便用户使用。所以FILE是C接口层面的概念,fd是系统调用层面的概念。

什么是FILE

  1. FILE是一个结构体,要想成功访问文件,那么FILE结构体中就一定有存储fd的变量。
  2. FILE是结构体_IO_FILE的重命名

如下是_IO_FILE的成员变量,_fileno是用于存放fd的


C缓冲区与内核缓冲区

什么是缓冲区?

缓冲区,是一块内存的空间,是用于存放数据的地方

有哪些缓冲区?

就我目前而知,缓冲区有用户级缓冲区(C语言提供的)以及内核缓冲区。

这两个缓冲区之间的关系?

用户先将数据刷新到用户级缓冲区,再等待合适的时机,将这些数据刷新到内核缓冲区。OS再根据自己的刷新策略将数据刷新到外设。

如何维护C缓冲区?

依靠FILE结构体,FILE结构体中有大量缓冲区相关字段

谈谈刷新时机

(访问文件,就是访问外设,访问显示器文件,就是访问显示器)

1.行刷新,碰到\n就刷新数据到内核缓冲区,通常是向显示器文件中写入

2.全缓冲,写满缓冲区才刷新数据到内核缓冲区,通常是向普通文件中写入

3.无刷新,直接刷新,不用等待,常见的是向stderr中写入

验证:

1.行刷新

按照我们上面说的,前面三个printf的内容会被刷到内核缓冲区,并打印到显示器上,后面三个不会

运行结果:

与预期一致

值得注意的是,我们在代码的末端加入了一个close(1),也就是说我这个进程无法再访问1所指向的文件,去掉close(1)会发生什么?????????

运行结果:

我们发现,所有的数据都被打印出来了,由此可以得到一个结论:进程退出时,缓冲区的文件也会被刷新到内核缓冲区中(前提是缓冲区文件向内核缓冲区刷新的通道没有被关闭,也就是close(1))

全缓冲

运行结果:

我们发现log.txt的大小是0,这足以说明:数据现在仍然存在于用户级缓冲区当中,还没有刷新到内核缓冲区,那么log.txt的大小自然是0

现在,我们让数据多写一些到用户级缓冲区当中去

运行结果

用户级缓冲区的数据果然刷新到了磁盘文件上。

无刷新

运行结果:

可以看到,我们既没有加\n,写入的数据大小也不是很大,但它仍然成功写入了stderr中(也就是显示器文件),这足以说明往stderr中写入时采用的是无刷新策略。


文件系统

大部分文件为普通文件,他们存储在磁盘上,当进程调用文件时才会被加载到内存之中。

所以磁盘是什么呢?

  1. 磁盘是大容量的存储介质,既可以输入又可以输出
  2. 磁盘的组成:盘面、磁头
  3. 盘面上:扇区、磁道
  4. 柱面

(上图转引自:Linux基础IO_读写文件时,更改起始读写位置的函数名字-CSDN博客

如何对存储在磁盘上的文件进行定位

1.确定文件所在磁头的那一个盘面

2.确定文件所在扇面的磁道

3.确定文件所在磁道的扇区

这就是CHS定位法

如何看待磁盘呢?

扇区是访问磁盘的基本单位(512byte),由于磁盘本质上是由一个一个的扇区组成的,因此整个磁盘可以被看作是一个很大的数组。

操作系统是管理软硬件的软件,所以他也会对磁盘做管理。由于磁盘空间太大,所以操作系统会对磁盘进去分组管理。

分区组成:是将磁盘分成若干个分区,每个分区由启动块,和块组组成

块组组成:

(以下六点转载自:Linux基础IO_读写文件时,更改起始读写位置的函数名字-CSDN博客

  1. Super Block: 存放文件系统本身的结构信息。记录的信息主要有:Data Block和inode的总量、未使用的Data Block和inode的数量、一个Data Block和inode的大小、最近一次挂载的时间、最近一次写入数据的时间、最近一次检验磁盘的时间等其他文件系统的相关信息。Super Block的信息被破坏,可以说整个文件系统结构就被破坏了。
  2. Group Descriptor Table: 块组描述符表,描述该分区当中块组的属性信息。
  3. Block Bitmap: 块位图当中记录着Data Block中哪个数据块已经被占用,哪个数据块没有被占用。
  4. inode Bitmap: inode位图当中记录着每个inode是否空闲可用。
  5. inode Table: 存放文件属性,即每个文件的inode。
  6. Data Blocks: 存放文件内容。以块为基本单位(4KB)

何为inode?

inode存放了一个文件的所有属性,它是一个结构体,大小是128字节,其中有两个成员变量为我们比较关注,inode number即inode编号,int blocks[NUM]即文件内容存储于哪些块中。

为什么要有inode编号?

一个文件一个inode,文件数量太多,也就是inode也太多,所以需要inode编号来对inode进行区分。

inode编号的作用?

主要用于查找一个文件的inode,找到了inode就知道了文件的属性,知道了文件的内容存储在哪里,也就可以对文件进行修改。可是我们查找文件都是使用文件名的,并不知道inode编号。目录会为我们解决这个问题——

Linux下一切皆文件,目录也是文件,它也有自己的inode结构和存储数据的块,它存储的就是当前目录下文件名与inode编号的映射关系。

如何删除一个文件?

inode bitmap与block bitmap置为0

如何新建一个文件?

根据目录的inode编号,找到当前分区,查询inode bitmap,为文件创建一个inode结构,并将文件属性填充进inode,将该文件的文件名和inode指针添加到目录文件的数据块中。


软/硬链接

什么是软链接:

软链接其实是指创造一个文件,使它存储的是另一个文件的绝对路径,该文件有自己独立的inode,这相当于windows操作系统中创建快捷方式的行为

如何使用软链接:

1.创建软链接(对softlink创造一个softlink-s的软链接)

运行结果一致

inode编号不同

软链接文件和源文件具有关联性,即源文件删除,软链接文件就无效了

什么是硬链接:

相当于对文件取别名,即inode编号相同,存储数据相同,但文件名不同

如何使用硬链接:

运行结果:

inode一致,文件大小一致

硬链接文件 与源文件具有独立性 ,既然一方被删除也不会影响另一方

?????

硬链接数:

硬链接数变成了2,对具有相同inode编号的文件来说,具有几个文件名就有几个硬链接数

特别的,对于目录来说,由于它的硬链接数默认是2,这是由于目录下有隐藏的.文件,它与目录有着相同的inode编号

以上便是对linux基础io的知识总结,各位大佬若有指教,欢迎在评论区留言,俺不胜感激!

文章来源:https://blog.csdn.net/m0_70693845/article/details/134733770
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。