Linux基础I/O(上)—— 文件详解

C语言文件I/O

写文件

没有指定文件的目录则会在当前目录下创建文件。

以"w"模式打开文件,会把原始内容清掉再写。

在这里插入图片描述

在这里插入图片描述


以"a"模式打开文件,会把在原始内容后面继续追加。

在这里插入图片描述
在这里插入图片描述

读文件

在这里插入图片描述

在这里插入图片描述

stdin & stdout & stderr

  • C默认会打开三个输入输出流,分别是stdin, stdout, stderr
  • 仔细观察发现,这三个流的类型都是FILE*, fopen返回值类型,文件指针
    在这里插入图片描述

当我们的运行C程序的时候,操作系统就会默认将这三个输入输出流打开,之后我们才能调用类似于scanf和printf之类的函数向键盘和显示器进行相应的输入输出操作。

所有的外设,本质核心操作就是 read 或 write。对于键盘文件,它的读方法就是从键盘读取数据到内存,对于显示器文件,如调用 printf 函数时,操作系统是要往显示器上写入的,其实你输入的命令是你通过键盘输入的,所以系统应该是往键盘读数据。至于用户能看到输入的命令,仅仅是为了方便用户,操作系统把从键盘输入的数据,一方面给了系统读取,一方面给显示器方便用户。

对于键盘
int read(…)
int write(…)

对于网卡
int read(…)
int write(…)

对于显示器
int read(…)
int write(…)

但不同的硬件,对应的读写方式肯定是不一样的
操作系统会为每一个底层硬件创建struct file结构体,此结构体中一定包含了两个函数指针,分别指向这个硬件对应的读方法和写方法

系统文件I/O

操作文件,除了上述C接口(当然,C++也有接口,其他语言也有),我们还可以采用系统接口来进行文件访问。
在这里插入图片描述

open

系统接口中使用open函数打开文件在这里插入图片描述

第一个参数

要打开或创建的目标文件

  • 给出文件名,若当前目录存在,则打开,否则在当前目录创建;
  • 若给出绝对路径,则在该路径下创建;

第二个参数

open函数的第二个参数是flags,表示打开文件的方式。打开文件时,可以传入多个参数选项,用下面的一个或者多个常量进行“或”运算,构成flags。

  1. O_RDONLY: 只读打开
  2. O_WRONLY: 只写打开
  3. O_RDWR : 读,写打开
  4. O_CREAT : 若文件不存在,则创建它。需要使用mode选项,来指明新文件的访问权限
  5. O_APPEND: 追加写

第三个参数

mode,表示创建文件的默认权限。

例如,将mode设置为0666,理论上文件创建出来的权限如下-rw-rw-rw-
但是实际上创建出来文件的权限值还会受到umask的影响,实际创建出来文件的权限为:mode&(~umask)。umask的默认值一般为0002,当我们设置mode值为0666时实际创建出来文件的权限为0664。也就是如下-rw-rw-r--

如果想使新创建出来的文件不受umask值的影响,那么仅需在创建该文件前令umask值为0,即umask(0);

不需要创建文件时,第三个参数可以不写

返回值

  1. 成功:新打开的文件描述符
  2. 失败:-1

close

在这里插入图片描述
参数 :被关闭文件的文件描述符1。
返回值:关闭成功,返回0;关闭失败,返回-1;

write

在这里插入图片描述
参数:将buf位置开始向后count字节的数据写入文件描述符为fd的文件当中。
返回值:写入成功,返回实际写入数据的字节个数;写入失败,返回-1;

read

在这里插入图片描述
参数:从文件描述符为fd的文件读取count字节的数据到buf位置当中。
返回值:读出成功,返回实际读取数据的字节个数;读出失败,返回-1;


测试
在这里插入图片描述

在这里插入图片描述


在这里插入图片描述

在这里插入图片描述

文件描述符fd

在这里插入图片描述

在这里插入图片描述

我们发现上述文件描述符是从3开始依次增加1的,那么,

  1. 0 ,1, 2去哪了?
  2. 文件描述符的分配规则又是什么呢?
 我们在上面提到了三个系统帮我们默认打开的三个流,stdin、stdout、stderr
 打开文件一定是进程运行的时候打开的
 而任何进程在运行的时候都会默认打开三个输入输出流
 即标准输入流、标准输出流以及标准错误流也就是stdin、stdout、stderr
 标准输入对应的设备是键盘,
 标准输出、标准错误对应的设备是显示器

我们在打开上述4个文件前如果close(0)会发生什么?
在这里插入图片描述

在这里插入图片描述

我们发现第一个文件的文件描述符变为了0

从结果中我们可以看出,文件描述符的分配规则是在files_struct数组当中,找到当前没有被使用的
最小的一个下标,作为新的文件描述符


文件描述符的本质

一个进程可以打开一个文件,一个进程也可以打开多个文件,所以在操作系统内可能同时存在大量文件,对于这些大量的文件要被操作系统先描述、再组织的管理起来;

要打开一个文件就要为其创建对应的文件对象struct file(被打开文件的描述结构体对象),以双链表管理起来这些struct file

那么进程和打开文件的对于关系又如何维护?

那么就有了struct files_struct,它里面包含一个数组struct file *fd_array[],
进程的task_struct中有一个指针struct files_struct *files指向struct files_struct对象,内核创建文件对象后将其的地址填入该数组struct file *fd_array[]

所以,本质上,文件描述符就是该数组的下标。所以,只要拿着文件描述符,就可以找到对应的文件
在这里插入图片描述
所以进程在访问对应的文件的时候,其实是先拿着文件描述符找到文件描述符数组中对应下标中的地址,再通过地址找到对应的struct file对象,再通过这个对象访问到磁盘中的文件。

相关推荐

  1. 2.Linux文件IO基础

    2024-02-06 01:08:01       20 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-02-06 01:08:01       14 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-02-06 01:08:01       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-02-06 01:08:01       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-02-06 01:08:01       18 阅读

热门阅读

  1. 《微信小程序开发从入门到实战》学习九十九

    2024-02-06 01:08:01       34 阅读
  2. C# Avalonia 11.0.6 绘图

    2024-02-06 01:08:01       29 阅读
  3. SQL的函数类型

    2024-02-06 01:08:01       35 阅读
  4. 【工具】使用asciidoctor-pdf将adoc文件转换成pdf

    2024-02-06 01:08:01       31 阅读
  5. linux使用docker安装rancher

    2024-02-06 01:08:01       27 阅读
  6. PyTorch的 torch.unsqueeze() 和 torch.squeeze()方法详解

    2024-02-06 01:08:01       23 阅读
  7. 2.5 作业

    2024-02-06 01:08:01       25 阅读
  8. P2SH地址嵌套SegWit脚本

    2024-02-06 01:08:01       30 阅读
  9. #vu3# element plus表格的序号字段

    2024-02-06 01:08:01       30 阅读
  10. 【Android-Compose】Material3 新版下拉刷新 PullRefresh

    2024-02-06 01:08:01       30 阅读
  11. 【工具介绍】Herbie:浮点数运算化简工具

    2024-02-06 01:08:01       32 阅读
  12. Qt中设置全局字体

    2024-02-06 01:08:01       33 阅读