栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

Linux操作系统--基础IO

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Linux操作系统--基础IO

Linux--基础IO]
  • C文件 IO 相关操作
  • 系统调用接口
    • 文件描述符 fd
  • 重定向
    • dup2系统调用
  • 文件系统
  • 动态库和静态库

C文件 IO 相关操作

有关c语言的IO函数
fopen、fread、fwrite、f等等
我们先来看一个简单的例子:打开一个文件

  • fopen函数的两个参数,第一个参数为文件路径,如果我们不加路径,只写文件名则指当前路径 —cwd
    什么是当前路径呢?本质是进程运行时所处的路径
    我们可以通过命令的形式看一看进程究竟在什么路径下
    我们知道除了 axj aux 这样的查看进程命令,还可以通过proc文件夹 来查看进程


我们可以清晰的看到,有一个exe 指 可执行文件所处的路径,cwd 指进程运行时的路径

  • 第二个参数为打开方式,总的来说,有b则是打开二进制文件,有+则一定是可读可写,其中r+为打开w+为新建有b为二进制


这个小小的例子就是打开一个用来写入的文件,要注意操作完要记着关闭文件,接下来我们尝试操作文件


fputs 将字符写入流中


fgets,将流中的内容写到缓冲区中,其中第一个参数为缓冲区,第二个参数则是我们预期输入缓冲区的大小

至此我们完成了大致的c语言文件操作,这里有几个细节
FILE* 是我们打开文件时的返回值,这里的文件类型可以是普通文本文件、二进制文件、设备文件等

还需要注意的是 ,进程运行时,会自动打开三个流文件,分别叫做标准输入、标准输出、标准错误,他们都在头文件中被声明,分别对应的设备为键盘、显示器、显示器。


因此,我们就可以通过fgets和fputs 来模拟printf和scanf

第三点:a和w分别为追加写入和覆盖写入,也就是从文末开始写 与 从文件开头开始写

以上就是大致c语言相关的io操作 ,当然还有fseek、ftell、frewind等等函数,我们这里不深入探究。


系统调用接口


我们上文中所使用的C语言IO函数,也就是c语言的库函数,它通过对系统调用接口的封装来让程序员轻易使用,接下来我们就聊聊更加底层的系统调用接口。
我们先来看看如何打开文件,叫做 open函数

它的参数有三个,第一个为我们所要打开的文件路径和文件名,这个与fopen相同
第二个参数为标志位参数,可以有O_RDonLY , O_WRonLY , O_RDWR 分别对应了只读 、只写、 可读可写。

除此之外,还有其他的标志位,比如 O_CREAT 我们可以发现 我们的系统调用接口与fopen有一些不同,fopen在文件不存在的情况下会自动创建,而open不可以,你需要写标志位O_CREAT 来增加这一功能。否则会打开失败,返回-1

第三个参数为我们创建文件时的权限值,所以如果文件已经存在 ,就不需要第三个参数了。

在此,我们来对第二个参数的标志位进行深入的了解:
我们可以认为有32个不同的标志位,因为我们在传参时,理论上可以传32bit位,标志位的本质就是一位为1,其余31位全部为0,来分别标志不同的状态。这也就解释了我们在进行标志时用 或 (|)这个运算符来处理。
这样比特位传递参数的方式就给我们许多的选线。

最后一个参数也有一些小细节,我们一定要输入四位的权限 ,第一位我们默认为0就好了,否则我们仅仅输入 666这样的码是无法完成权限的赋值的。
其中在赋值权限时,还要注意 umask这样的掩码,我们可以在打开文件前将掩码赋为0。
我们就可以轻易的赋值权限了。

最后我们来谈谈open的返回值,让我们意想不到的是它为int ,而我们fopen的返回值为FILE * 。
open的返回值:成功 返回file descriptor – 文件描述符 ,失败则返回 -1
我们可以打开多个文件,发现他们的fd值是从3开始的连续整数。
有两个问题:1.为什么没有0、1、2
2.为什么它是连续的,很容易让人想到数组

文件描述符 fd

我们回答第一个问题,我们还记得之前说过进程运行时会自动打开3个流,其中0就是 stdin的 fd, 1就是stdout 的 fd, 2 就是 stderr 的 fd。所以我们在打开第四个文件时,其返回值fd会为3 。我们可以想到,这三个流也是被打开的文件,所有文件都会在打开时有一个fd值。我们所谓的文件描述符就是数组下标,之后打开的文件会依次被赋予fd值。当然这是大致的了解。

我们现在就来看看文件描述符的底层逻辑:
我们的文件可以分为两种:1.磁盘文件 2.内存文件

磁盘文件:
就是我们保存在磁盘中的文件,这个文件会在进程调用它的时候进行加载到内存的操作,类似于我们的程序替换这样的加载器。这个文件的组成为:内容+属性,属性比如创建时间、文件大小、所属组、修改日期等等这样的信息 , 也称作 元信息 ,而内容就是我们打开所看到的内容。

内存文件:
当我们进程需要一个打开或是操作一个文件的时候,我们操作系统会为这个文件生成一个struct file 这样的文件描述结构体,其中大多包含了文件的元信息。一个个这样的结构体会形成双链表,让我们管理。在这之前,在进程创建的时候,还会生成一个struct files_struct 这样的结构体,这个结构体被pcb内的指针所指向,用来管理文件。其中这个结构体中有一个部分为一个指针数组,struct file* fd array[32] ,这里的每一个指针就会指向我们文件的struct file。而这里的数组下标就是我们所知道的文件描述符。其中这个文件描述符所在的数组是可以扩展的。所以我们每打开一个文件,都会有文件描述符指针指向它,并且它的指向是有特性的:也就是依次从小到大指。

我们都知道,一个系统中会有无数已经被打开的文件,所以我们通过这样的方式对文件进行管理。
当然这些结构体都处在内存中。

如果我们需要对一个文件进行操作,不是一下将磁盘中的全部文件拷贝到我们的内存中,而是通过缓冲区,延后式的加载到内存中让我们操作。
比如我们打开一个log.txt文件,并被赋予了3号fd , 我们现在read(3,xx,yy),此时执行到read这一步时才会通过我们的文件描述信息struct file 将文件加载到内存中。
此时如果我们close (1)这个stdout文件,那么我们在打开文件时,log.txt会被分配到 1号fd。
以上就是我们文件描述符的底层实现,它的分配规则就是从最小但是没有被使用的fd开始分配。

重定向

重定向的本质:就是修改文件描述符fd下标所对应的 struct file * 的内容。
比如原本 1 号fd 指向 stdout ,而现在让其指向了 log .txt ,这就叫做重定向

dup2系统调用 文件系统 动态库和静态库
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/313159.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号