Linux---基础IO

预备知识 

文件=属性+内容

1.所有对文件的操作:a、对内容做操作 b、对属性做操作

2.内容是数据,属性也是数据----存储文件,内容和数据都要被储存----默认储存在磁盘中

3.我们(进程)要访问一个文件的时候,要先把文件打开,本质就是将文件从磁盘加载到内存,涉及硬件,由操作系统来做

4.一个进程可以打开多个文件,多进程可以打开多个文件,即打开的文件可能有多个

那么操作系统如何来管理这么多的文件呢?先描述,在组织

一个文件要被打开,首先要先在内核中形成一个文件对象(struct file)

5.文件按照是否被打开分为:被打开的文件(内存中) 没有被打开的文件(磁盘中)

6.进程和被打开的文件的关系

C语言文件接口回顾

具体的讲解参考C语言文件操作 

我们知道用户是无法直接访问硬件的,而文件在磁盘上,所以我们必然需要通过操作系统来帮我们打开文件,而上面的代码中我们调用的都是C语言接口,没有用操作系统的接口,我们是如何做到的呢?答案其实很简单:C语言的文件操作接口就是对操作系统相关接口进行封装得来的,所以底层依旧是操作系统在干活。

那么操作系统的文件相关接口有哪些?


一、操作系统的相关文件接口

注意:O_RDONLY | O_WRONLY  和  O_RDWR 不等价!!!想要读写都有只能写O_RDWR

该函数的返回值为整形,相当于C语言接口的返回值FILE*,都是用来识别文件的,使用如下

很显然该文件的权限是乱码,那么如何创建一个文件并同时规定它的权限呢?跟mode这个参数有关,使用如下

有人可能又要问了,我们设置的权限都是rw-,为什么其他人的权限为r--,不要忘了有掩码umask,当然我们也可以在代码中改变umask的值,这里不建议这么做

那么如何向文件中写入呢?


二、open函数的返回值fd

open函数它的返回值是什么,我们还不了解,但是我们知道它一定能帮我们找到对应的文件,我们先来打印几个看看

它的返回值是一连串的整数,看着像是数组下标,还缺了前3个,具体的情况如下


三、再次理解一切皆文件

所有的硬件设备都会有输入输出,在系统看来就是读写,无论你是只读,只写还是只读写。当然不同设备的读写的具体操作会有所不同,但是我们不关心,我们只要能使得不同的设备调用它自己的读写函数,从而完成特定的功能即可, 在上层来看就是该设备完成了读写任务,这么一看是不是和面向对象的多态一样,所以Linux系统中讲一切皆文件


理解file结构体


fd的分配规则

从之前的打印结果来看,fd是按照顺序分配的,但如果我们先关掉一个文件,再打开一个文件,那么该文件的fd是按顺序呢,还是填补最小的下标呢?

很显然,fd的分配规则是按照最小的没被分配的下标进行分配的

现在我们可以反过来去验证一下前面三个stdin,stdout和stderr是否默认打开

总结:

1、标准输出、标准输入和标准错误是默认打开的

2、fd的分配规则是找最小的没被分配的下标进行分配

现在我们来看看下面这两段代码和运行结果

1、都没有在屏幕上打印

2、一个log.txt文件中出现了本来要在屏幕上打印的数据,另一个啥都没有

第一个现象很好解释,因为我们将标准输出关了,当然不能在屏幕上打印

第二个现象结合上面讲的,其实也不难理解,由于标准输出被关了,所以标准输出对应的1就被分配给了新打开的文件log.txt,而printf函数默认在屏幕上输出,本质就是默认在文件描述符1所对应的文件中输出,而现在log.txt就是这个stdout,所以打印语句的内容出现在了log.txt中,但是我们发现只有加上fflush函数刷新stdout的缓冲区才能实现这个效果,这个后面会具体讲(其实本质是文件缓冲区是语言范畴的,而我们调用的是系统接口关闭文件,不会把在缓冲区中的内容刷新到文件中,需要手动调用fflush)

好,理解上面的现象之后,我们会发现它跟重定向很相似,或者说重定向的底层就是这样实现的

四、重定向

上面的代码是输出重定向,下面同理,分别是追加重定向和输入重定向

但是这种方法实现的重定向有点太挫了,有没有高级一点的方法呢?我们理解一下上面三个实现重定向代码的底层逻辑就会发现它们都是将文件描述符0/1对应的标准输出和输入改成其他文件就行

根据这个原理,操作系统实现了一个接口dup2

dup2就是将newfd覆盖为oldfd,演示如下


接下来,我们来讲讲标准错误stderr

上面是关于标准错误的一些用法,其实从中不难看出为什么要有标准错误,因为我们可以将程序正常运行的打印信息和程序异常的打印信息分开来输入到两个文件中,方便我们观察,纠错

五、缓冲区

缓冲区,简单来说,就是给我们暂时存放数据的一块空间,我们可以把它理解成快递站,当我们要寄东西出去的时候,我们会将物品交给快递站,然后由快递站帮我们发送,一般来说,快递站会等物品数量到达一定程度才会发货,以此提高效率降低成本,缓冲区也是同理,它会等数据量到达一定程度,才会将数据刷新到内存。(1.用户不用在管这些数据,提高使用者效率 2.提高发送效率)

刷新缓冲区也分为立即刷新,按行刷新和缓冲区满了再刷新三种方式,当然在一些场景下,也需要强制刷新这一操作,比如进程退出前,我们需要将还在缓冲区的数据强制刷新到内存中。

一般对于显示器文件,行刷新

对于磁盘上的文件,全缓存(缓冲区写满了,在刷新)


我们来看下面这两段代码 

当我们都在显示器上打印的时候,打印的内容一样,但是一旦将数据打印到文件log.txt中时,右边的文件中多出了三行(除了系统接口函数,C的打印语句都打印了两遍,且系统接口打印的内容到了第一行),上面两段代码的唯一不同在于右边多了一个子进程的创建语句。

为什么呢?这个现象出现的原因是什么呢?

肯定和fork有关,但是我们知道fork创建子进程,不会影响代码的执行顺序,也就是说前面四个打印语句执行完了,就不会在执行了,那为什么打印到文件的内容增加了呢???

理解如下

1.当我们直接往显示器文件打印的时候,显示器的刷新方式是行刷新,而我们的打印语句都有\n,fork之前,所有的数据都已经被刷新

2.重定向到log.txt,本质是向磁盘在文件中写入,刷新方式就变成了全缓存

3.全缓存意味着缓冲区变大,我们写入的数据不足以将缓冲区填满,所以在fork执行的时候数据依旧还在缓冲区中

4.我们现在说的缓冲区和操作系统无关,只和C语言本身有关,因为printf、fprintf、fputs底层都是调用的write,而write语句的打印只出现了一次

5.C/C++提供的缓冲区,里面一定保存的是用户的数据,属于当前在运行的进程,但是如果我们把数据交给OS,这个数据就属于OS,不在属于用户

6.当进程退出的时候,一般要进行刷新缓冲区,即便你的数据没有满足刷新条件,而刷新缓冲区就涉及对数据做修改,那么当父子进程中的一个进程结束刷新缓冲区时,就会发生写实拷贝,从而导致打印的数据变多,而write是系统接口,打印的内容直接在OS中,和C语言的缓冲区没有关系,所以write打印语句只会打印一次

那么缓冲区在哪里呢???

我们知道系统通过文件操作符来找到文件,C语言通过FILE指针来找到文件,而FILE结构体中包含了文件操作符,缓冲区也在它里面,具体如下

(该结构体会被重定义为FILE)

原文地址:https://blog.csdn.net/V_zjs/article/details/134575129

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


linux常用进程通信方式包括管道(pipe)、有名管道(FIFO)、信号(signal)、消息队列、共享内存、信号量、套接字(socket)。管道用于具有亲缘关系的进程间通信,有名管道的每个管道具有名字,使没有亲缘关系的进程间也可以通信。信号是比较复杂的通信方式,用于通知接受进程有某种事件发生,除
Linux性能观测工具按类别可分为系统级别和进程级别,系统级别对整个系统的性能做统计,而进程级别则具体到进程,为每个进程维护统计信息。

按实现原理分,可分为基于计数器和跟踪以及剖析。含义如下:

计数器:内核维护的统计数据,通常为无符号整型,用于对发生的事件计数,比如,网络包接收计数器,磁
本文详细介绍了curl命令基础和高级用法,包括跳过https的证书验证,详细追踪整个交互过程,可用于调用网络后端接口,诊断http和https网络服务故障。
本文包含作者工作中常用到的一些命令,用于诊断网络、磁盘占满、fd泄漏等问题。命令包括ping、fping、tcpdump、lsof、netstat、/proc/$pid/fd、du、grep、traceroute、dig。
linux的平均负载表示运行态和就绪态及不可中断状态(正在io)的进程数目,用uptime查看到负载很高,既有可能是CPU利用率高,也可能是大量在等待io的进程导致,用mpstat查看每个CPU的使用情况,查看CPU的使用率或者CPU花在等待io的时间,接着用pidstat定位具体的进程
CPU上下文频繁切换会导致系统性能下降,切换分为进程切换、线程切换及中断切换,进程切换的开销较大,除了需要保存寄存器和程序计数器中的值还需保存全局变量、栈等到内存中,以便下次运行恢复,而同一进程中的线程切换开销会小很多,只需更新寄存器和线程独有的栈,共享资源如打开的文件、全局变量等无需切换,当硬件中
1.top命令 作用:该命令可以按CPU使用.内存使用和执行时间对任务进行排序,常用来监控系统中占用CPU或内存较高的程序及CPU和内存的负载。 默认视图: 当想看系统负载时,可观察汇总的%CPU中的us用户进程和sy系统进程是否占用CPU很高,相加接近100%就说明占用很高了,有些程序可能得不到及
文章浏览阅读1.8k次,点赞63次,收藏54次。Linux下的目录权限!!!粘滞位!!!超详解!!!
文章浏览阅读1.6k次,点赞44次,收藏38次。关于Qt的安装、Windows、Linux、MacBook_mack book 安装qt
本文介绍了使用shell脚本编写一个 Hello
文章浏览阅读1.5k次,点赞37次,收藏43次。【Linux】初识Linux——了解操作系统的发展历史以及初次体验Linux编程环境
文章浏览阅读3k次,点赞34次,收藏156次。Linux超详细笔记,个人学习时很认真的记录的,觉得好的麻烦点个赞。
文章浏览阅读6.8k次,点赞109次,收藏114次。【Linux】 OpenSSH_9.3p1 升级到 OpenSSH_9.5p1(亲测无问题,建议收藏)_openssh_9.5p1
文章浏览阅读3.5k次,点赞93次,收藏78次。初识Linux中的线程,理解线程的各种概念,理解进程地址空间中的页表转换,介绍pthread线程库并理解线程库!
文章浏览阅读863次。出现此问题为Linux文件权限问题,解决方案为回到引擎目录执行命令。输入用户密码后运行./UnrealEditor。_increasing per-process limit of core file size to infinity.
文章浏览阅读2.9k次。使用文本编辑器:打开CSV文件,并使用文本编辑器(如Notepad++、Sublime Text、Visual Studio Code等)来查看文件的字符编码格式。通常在编辑器的底部状态栏或设置中可以找到当前编码的显示。请注意,上述方法并非绝对准确,特别是当文件没有明确的编码标识时。因此,如果你发现CSV文件在不同的工具或方法中显示不同的编码格式,可能需要进行进一步的分析和判断,或者尝试使用不同的编码转换方法。该命令将输出文件的MIME类型和编码信息。使用命令行工具:在命令行中,你可以使用。_shell读取csv文件逐行处理
本文介绍了如何在Linux系统中升级gcc版本,以便更好地支持C++11及以上版本的新特性。通过升级gcc,可以提升编译器的功能和性能,获得更好的开发体验。详细的步骤和方法请参考原文链接。
文章浏览阅读4.4k次,点赞6次,收藏19次。Mosquitto是一个开源的MQTT消息代理服务器。MQTT是一个轻量级的、基于发布/订阅模式的消息传输协议。 mosquitto的安装使用比较简单,可以方便的来进行一些测试。_linux mosquitto
文章浏览阅读7.2k次,点赞2次,收藏12次。Linux中,用于根目录下有一个.ssh目录,保存了ssh相关的key和一些记录文件。_~/.ssh/
文章浏览阅读4.5k次,点赞5次,收藏18次。首先需要安装 snmp ,使用下面的命令进行安装安装完毕之后,使用下面的命令查看是否安装成功当命令行显示如图即为安装成功。_snmp工具