学习系统编程No.12【基础IO】

这篇具有很好参考价值的文章主要介绍了学习系统编程No.12【基础IO】。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

引言:

北京时间:2023/3/28/7:19,周二,早八的一天,难过!终于进入C站周创作榜啦!开心!给大家推荐一首歌《盛夏的果实》,给我的感觉非常的放松,劳逸结合,音乐非它莫属,为了下周周榜可以继续前进,今天我们就来学习一下基础IO的知识吧!

学习系统编程No.12【基础IO】

回顾重定向

从上篇博客,我们明白,重定向不过只是关闭在文件描述符表下标为0 1 2 默认打开的标准输入、标准输出和标准错误,然后把新文件打开,然后占用文件描述符表中的0 1 2 下标,因为上层并不在乎下标中的文件对象地址是否是标准输入等,而是直接向该下标中的文件对象地址写入;并且我们要明白 ,标准输入文件本质上指向的就是我们的键盘,标准输出和标准错误本质上指向的是显示器, 所以标准输出和标准错误都应该是往显示器打印的,但是如下图所示:

学习系统编程No.12【基础IO】
我们可以发现,当我们使用了输出重定向(“>”),此时它会把标准输出文件关闭,然后使用新打开的文件占用原标准输出的在文件描述符表中的下标处的指针指向的地址,所以可以很好的看到,当我们运行可执行程序的时候,此时向标准输出打印的内容已经看不到了,只能看到向标准错误中打印的内容,这也就表示,stdout,cout 都是往文件描述符下标为1对应的文件对象打印,stderr,cerr 都是往文件描述符下标为2对应的文件对象打印,并且此时输出重定向改的只是1下标对应的指向,并不会影响2号,所以导致2下标继续向显示器打印,因为上述的本质,标准输出和标准错误本质上都是向显示器打印,但是使用输出重定向并不会影响下标2,所以不影响向标准错误中打印的数据,所以在我们的显示器上依然可以看到标准错误需要打印的数据,但是向标准输出中打印的数据却不能在显示器上看到,而是只能在重定向的新文件中看到,也就是log.txt中看到了,因为重定向导致此时的标准输出文件地址变成了log.txt。

所以通过上述的知识,我们就可以知道,标准输出和标准错误本质上都是向显示器打印,只是路径有一些不同而已,标准输出是向文件描述符表下标为1处指针指向的文件对象写入,而标准错误是向文件描述符表下标为2处指针指向的文件对象写入,所以此时如果我们有一个需求,就是将一个程序中的正常信息,打印到logNormal.txt中,把错误消息打印到logError.txt当中,目的就是为了区别错误信息和正常信息此时应该怎么办呢?
基本思路:
将文件描述符表中的下标1和2对应的标准输出和标准错误文件给关闭,然后打开我们想要接收信息的文件,此时程序对应的错误信息和正常信息就可以很好的打印到对应的文件之中了,具体代码如下:

学习系统编程No.12【基础IO】

所以使用上述的方法,就可以很好的把文件中的不同类型的信息给区分开来,当然在实际中,并不需要这么麻烦,因为在Linux指令中,Linux系统已经为我们提供了重定向的接口("<",">"),我们就可以直接使用从定向的接口,来完成相应的操作,让系统自己帮我们去关闭对应的文件描述符表中的对应的下标指针指向的文件,指令./a.out 1>logNormal.txt 2>logErrno.txt ,表示的也就是上图中的功能,本质上就是系统对我们上图所示代码通过 "<",">" 做了一定的封装效果而已,不管怎样都还是要去关闭标准输入、标准输出或者标准错误,然后打开对应的新文件,因为原理就是这样如此!

注意: ./a.out > log.txt 2>&1 意思是将标准错误和标准输出放到同一个文件中,意思:2重定向为1的地址

重定向接口(dup2)

明白了上述,此时发现像我们以前的写法,先关闭标准输入、标准输出或者标准错误文件,然后再打开一个新文件,这样的写法是比较麻烦的,所以我们可以直接使用dup2这样的重定向函数,使用方式:int dup2(int oldfd,int newfd);,但是值得我们注意的是,此时需要把newfd和oldfd给区分一下,如下图:
学习系统编程No.12【基础IO】
按照使用原理中的解释,表明newfdoldfd的一份拷贝,并且因为我们是需要把新文件的fd去替换到标准输出文件(1),所以可以知道,最后剩下的肯定是新文件的fd,所以明白新文件的fd就是oldfd具体使用如下图所示:

学习系统编程No.12【基础IO】

深入缓冲区

在上篇博客中,在讲一切皆文件的时候,我们已经浅浅的认识了一下缓冲区,所以我们承接以前的内容,来深入一下缓冲区,来看看缓冲区到底有什么用呢?
学习系统编程No.12【基础IO】
如上图,我们知道,在 struct file 文件对象中,是存在着缓冲区的概念的,并且明白,当操作系统需要写数据到相应的外设中,那么此时第一时间就是将数据拷贝到文件对象的文件缓冲区中,然后让文件对象中的相关函数指针去和外设的驱动程序进行交互,最终把文件对象中的文件缓冲区中的数据按照缓冲区对应的刷洗策略给刷新到外设中 ,所以让我们按照这个原理,来深入认识一下文件缓冲区吧!

首先我们看一个现象,这个现象可以很好的证明缓冲区的刷新策略等知识!

如下图:

学习系统编程No.12【基础IO】

高能知识点:综合性非常高
要把FILE结构体和文件对象(struct file)搞明白,就要知道 struct FILE ,并不等于是 struct file ,其中,struct file是操作系统为了更好的管理文件,创建的文件对象,所以本质上,该结构体是属于系统级别的结构体,而struct FILE是用户调用系统调用接口,自己封装出来的一个结构体,本质上是属于用户级别,例:封装一个C库,然后使用C库中的库函数fprintf函数来调系统调用接口 write ,此时调用C库中的fprintf函数,它的第一步不是直接去调用系统调用,而是先malloc一个FILE结构体,因为如我们之前所说,在FILE结构体中才拥有指向文件描述符表的指针和缓冲区,所以fprintf函数想要调用write函数,前提一定是要有fd(通过指向文件描述符表的那个指针获得),其次是要有缓冲区,也就等于fprintf函数一定要有FILE结构体,然后才可以去调用write接口,并且调用write接口时,也是把FILE结构体中的fd文件描述符通过传参的形式传递给它,然后系统调用接口write才根据文件描述符找到对应的文件对象(struct file),最终把需要写入的数据拷贝到struct file文件对象对应的缓冲区中(该缓冲区目的:提高写入效率),并且根据文件对象中指向外设驱动程序的读写接口的函数指针实现将数据写入相应的外设

大致关系: C库( fprintf()->FILE->struct FILE(fd),缓冲区),表明缓冲区就是在C库中的,并且C库文件结构中,最主要的就是struct FILE结构体,因为该结构体中有缓冲区和指向文件描述符表的指针,也就是有fd,所以当我们在调用fprintf打印数据的时候,此时这个被打印的数据,并不是直接通过系统调用访问操作系统,然后找到文件描述符,然后找到对应的文件对象,然后通过文件对象写入到外设(显示器),而是只是把数据放到了对应的缓冲区当中,然后此时C库就会根据对应的缓冲区的刷新策略把缓冲区中的数据刷新到外设中(具体如何刷新到外设的)原理:调用系统调用接口write,然后根据FILE中的指向文件描述符表的指针,找到文件对象的fd,然后通过文件对象,将数据写入外设,(再次强调,FILE结构体不是文件对象结构体,虽然二者都有缓冲区,但是后者的缓冲区目的只是为了提高效率)

注意点: 就是fd是文件描述符,并不是指向文件描述符表的指针,所以此时跟C库是没什么关系的,本质上fd就是在FILE结构中的,原因,只有FILE结构中有指向文件描述符表的指针,所以FILE结构体就可以通过这个指针拿到对应的fd

C库中缓冲区的刷新策略:

(1.)全缓冲:在这种情况下,当填满标准I/O缓存后才进行实际I/O操作。全缓冲的典型代表是 对磁盘文件的读写 。

(2.)行缓冲:在这种情况下,当在输入和输出中遇到换行符时,执行真正的I/O操作。这时,我们输入的字符先存放在缓冲区,等按下回车键换行时才进行实际的I/O操作。典型代表是 标准输入(stdin) 和 标准输出(stdout) 。

(3.)无缓冲:也就是不进行缓冲,标准出错情况stderr是典型代表,这使得出错信息可以直接尽快地显示出来

所以此时可以明白,标准输入、标准输出的刷新策略是行缓冲,标准错误的刷新策略是无缓冲,普通文件采用的刷新策略是全缓冲

缓冲区最重要的意义:节省调用者的时间,本质因为系统调用需要花费时间

明白了上述的知识,所以此时关于缓冲区的第一个问题(也就是上图),就可以得到解释了,问题:为什么向标准输出中打印是两条语句,而向重定向文件中打印就是三条语句呢?原因,就是缓冲区的刷新策略,并且如果使用write接口,那么操作系统此时是直接将数据写入到文件对象中,但是如果使用的是fprintf,此时根据C库中FILE结构体中的缓冲区,此时就需要根据该缓冲区的刷新策略来把该数据刷新到文件对象中,并且此时因为,我们是向标准输出中打印,并且带了 \n ,所以此时根据C库缓冲区的原则,stdout是使用行缓冲(前提带 \n ),所以此时该fprintf函数打印的数据符合要求,所以直接就被写入到了文件对象中,然后我们再调用fork()函数创建子进程,那么此时就会因为接口都调用完了,数据也被写入完了,所以fork()函数没有现象,但是如果你是向一个重定义文件中写入,那么此时就会因为,C库中缓冲区对于普通文件的刷新策略是全缓冲(就是等buff数组满了再刷新到文件对象中),write因为是系统接口,所以同理,会直接将数据写入到文件对象,所以此时因为fprintf中的数据因为全缓冲,不能写入文件对象,所以当调用fork()函数创建了一个子进程之后,该进程也会执行对应的打印,所以导致最后出现了三条语句。

综上:缓冲区的设计非常的高级!

北京时间:2023/3/29/0:01
学习系统编程No.12【基础IO】文章来源地址https://www.toymoban.com/news/detail-420001.html

总结:今天有点晚了,明天还要晨跑,哎!苦命的孩子!撤!

到了这里,关于学习系统编程No.12【基础IO】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 学习系统编程No.7【进程替换】

    北京时间:2023/3/21/7:17,这篇博客本来昨天晚上就能开始写的,但是由于笔试强训的原因,导致时间用在了做题上,通过快2个小时的垂死挣扎,我充分意识到了自己做题能力的缺陷和运用新知识的缺陷,所以我需要把重心给转移一下了,以后做题才是我的头号目标,虽然我在

    2024年02月21日
    浏览(29)
  • 学习系统编程No.17【vscode实战】

    北京时间:2023/4/11/7:25,昨天11点洗澡,洗完直接睡,导致现在头发愈发不能看,So,平头时刻将要来临,头发太长真的很不方便,昨天已经更文啦!这个星期一定要实现日更,因为我发现,不日更,或者说更文不积极,根本上不了热榜,所以今天又有新文章和大家见面哦!

    2023年04月14日
    浏览(77)
  • 学习系统编程No.25【核心转储实战】

    北京时间:2023/6/16/8:39,实训课中,大一下学期最后有课的一天,还有两天就要期末考啦!目前什么都还没有复习,不到星期天晚上,咱不慌,小小挂科,岂能拦得住我补考,哈哈哈!小事,莫慌,该篇博客出炉之时,就是我复习之日,临阵磨枪不快也光,这方面我是专业的

    2024年02月11日
    浏览(37)
  • 学习系统编程No.14【动静态库】

    北京时间:2023/4/3/7:06,刚刚晨跑回来,为了摆脱困意,刷了一下视屏,哈哈哈!我发现我每次刷视屏都是被迫的,都是看到某个感兴趣的标题,然后点进去一看,就不能自拔了,所以我下次得把消息提醒给全部关掉,烦人;并且全宿舍英文4级都报上了,就我没报上,真的是

    2023年04月09日
    浏览(41)
  • 学习系统编程No.16【进程间通信】

    北京时间:2023/4/9/20:44,昨天,也就是这个周末的星期六,就是传说中的蓝桥杯,哈哈哈!摆烂,做题方面真不怎么行,可惜,当初可能是年少轻狂或者说是没什么经验阅历,希望在有了这次的经历之后,明年的今天,能够更加从容吧!谁让我们平时不怎么做题呢?准确的来

    2023年04月15日
    浏览(39)
  • 学习系统编程No.32【线程互斥实战】

    北京时间:2023/7/19/15:22,昨天更新完博客,和舍友下了一会棋,快乐就是这么简单,哈哈哈!总体来说,摆烂程度得到一定的改善,想要达到以前的水准,需要一定的契机,毕竟人生在世,快乐最重要是吧!更文带给我的快乐已经没有那么多了,虽然欠了非常多的作业,非常

    2024年02月16日
    浏览(24)
  • 学习系统编程No.33【生产消费模型】

    北京时间:2023/7/22/14:27,现实和预期往往相差是巨大的,哈哈哈!白天睡不醒,晚上睡不着,就像一个夜猫子一样。熬夜耍手机,我真的是专业的,已经连续好久没有正常睡过觉了。怀念学校里的日子,每天都有人激励我早睡和早起,此处@谢xx,不知他最近的学习状态如何,

    2024年02月14日
    浏览(30)
  • 学习系统编程No.30【多线程控制实战】

    北京时间:2023/7/7/9:58,耳机正在充电中,所以刚好让我们先把引言写一写,昨天睡觉前听了一会小说,听小说的好处就在于,它可以让你放下手机,快速睡觉,并且还有一定的助眠效果,但是最近有点书荒,所以听小说不是很积极,平时睡觉也就控制不住,昨天把很久以前看

    2024年02月15日
    浏览(34)
  • 学习系统编程No.26【信号处理实战】

    北京时间:2023/6/26/13:35,昨天12点左右睡觉,本以为能和在学校一样,7点左右起床,设置了7点到8点30时间段内的4个闹钟,可惜没想到啊,没醒,直接睡到了12点,看来下次不能给自己太高的期望,哈哈哈!在家没办法呀,习惯睡到12点了,想要解决这个问题,最好的方法就是

    2024年02月11日
    浏览(30)
  • 学习系统编程No.11【重定向的本质】

    北京时间:2023/3/27/7:05,哈哈哈,首先是开心,因为上篇博客热榜目前第15,让我初步掌握了上热榜的小妙招,不单单只是要日更,还有非常多的上榜小技巧,但是首先连续更新的占比还是比较大的,好像连续更新上榜的概率更大,所以让我们开始连续更新吧! 今天我们就来

    2023年04月15日
    浏览(26)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包