北京时间:2023/3/27/7:05,哈哈哈,首先是开心,因为上篇博客热榜目前第15,让我初步掌握了上热榜的小妙招,不单单只是要日更,还有非常多的上榜小技巧,但是首先连续更新的占比还是比较大的,好像连续更新上榜的概率更大,所以让我们开始连续更新吧!今天我们就来学一学真正的基础IO、文件系统和承接上文的部分知识,如缓冲区、重定向等!So,here we go!

当操作系统需要访问文件对象时,第一时间就是找到该进程对应的pcb,然后从该pcb中找到指向文件描述符表的指针,通过这个指针找到文件描述符表,进而找打文件描述符表中的各个文件对象的地址,所以在进程看来,它访问的都是一个一个的文件对象而已,根本没有和外设的驱动程序进行交互,因为这个工作已经被文件对象中的读写函数指针给搞定了,并且如果操作系统需要读写数据到相应的外设中,那么此时第一时间就是将数据拷贝到文件对象的文件缓冲区中,然后让文件对象中的相关函数指针去和外设的驱动程序进行交互,进而把数据读写到外设中,所以这就是为什么在Linux操作系统中一切皆文件的原因了,具体如下图所示:

这种结构或者说这样设计的好处就是:无论底层怎样差异化,我们通过文件对象中的函数指针的方式都可以很好的屏蔽这些差异,让操作系统通过进程,进程通过文件对象把数据准确无误的拷贝到相应的外设中或者是读取外设中的数据。并且这种做法就是传说中的多态,一个面向对象的过程;并且因为我们想用访问操作系统,只能通过进程的方式,所以无论我们用什么方式访问,我们都是用进程的方式去访问操作系统,然后因为进程只能看到文件,所以对于我们来说,我们看到的也就是一切皆文件
首先,通过上述的知识,我们明白了,操作系统想要访问一个文件,就必须找到该文件对应的进程,找到进程对应的文件描述符表,最终根据地址找到文件对象,如果找不到文件对象,就访问不了相对应的外设,并且任何语言想要访问外设或者文件,必须贯穿体系结构,调用系统调用,经历操作系统,所以我们现在写代码使用的头文件本质都是在调用一个一个的库(C库),通过这些库的封装,去调用系统接口,进而通过操作系统到进程,通过进程到文件描述符表,最后在文件描述符表中找到对应的文件,所以明白,C库本质调用它时,它就会被放在一个可执行文件中,所以C库本质可以理解就是一个进程,用户通过进程就可以去调用操作系统,并且操作系统想要找到对应的文件,又需要根据该进程(此时就是C库),因为只有该进程中有指向文件描述符表的指针,进而操作系统通过该进程中的指针找到文件描述符表,然后找到文件,所以明白最重要的一个道理 , 就是我们的进程中一定是需要有指向文件描述符表的一个指针,并且因为此时C库就是调用操作系统的那个进程,所以明白,C库中一定有指向文件描述符表的指针, 明白这个道理之后,再明白一个道理:
上篇博客中,我们已经了解了语言层面的文件操作(fopen,fclose,fread等),但是我们会发现,无论使用什么接口,此时都需要使用一个FILE* 的指针来接收该接口的返回值,所以FILE* 到底是什么呢?通过上述对C库的理解,我们知道,C库中一定有一个指向文件描述符的指针,并且明白,C库中的文件操作函数是通过封装系统调用接口(open、close、read等)实现了**,所以我们可以推测FILE是一种数据类型,是一个结构体**,明白 FILE 就是C库里面封装的一个结构体,此时在该结构体中,就存在着各种系统接口的封装和指向文件描述符的指针, 并且在使用的时候,就是通过这个指向文件描述符的指针去找到对应的文件地址,然后把这个地址传给封装的接口(fopen),最后通过这个封装的接口,把地址传给系统调用的接口(open);如下图所示:就是Linux系统中C库中的FILE结构体封装

所以明白了这两点之后,我们就明白了语言层面的文件操作的具体原理了,如下图,证明我们的语言层面封装的库中存在指向文件描述符表的指针:

通过上篇博客中对文件描述符的认识,此时我们明白,当一个进程创建只是,操作系统是默认已经打开了三个文件:标准输入、标准输出和标准错误,并且知道,它们对应的在文件描述符表中的下标是0 1 2 ,并且明白一个道理,就是在进程中,如果该进程对应的代码数据,具有打开文件的操作,此时操作系统就会把在磁盘中对应的文件加载到内存,然后创景一个文件对象(struct file),并且会把该文件对象的地址给给文件描述符表保管(目的提高效率),并且在文件描述符表中存储该地址的时候,是按照一定的规律的,并不像是物理内存一样,放在一个随机的地方,而是按照统一原则,将最小的没有被使用的数组元素(也就是那个下标),分配给该被打开的文件对象的地址 ,如下图右侧所示,此时进行了5次文件的打开,所以在文件描述符表中,就是从0 1 2 之后的下标3 4 5 6 7 开始存放相应的文件对象地址(虽然是同一个文件,但是不影响,考虑的是打开该文件的次数),但是如果此时你像右边图片一样,把标准输入文件给关闭,也就是等于将文件描述符表下标为0中的地址给清空掉,此时操作系统就允许你往该下标中存放文件对象的地址,所以右图的打印就是0 3 4 5 6(文件描述符的下标对应的就是文件的返回值)
如图深入文件描述符表的理解:

搞懂了上述现象是为什么,此时我们就深入看看下图的现象,正式了解重定向的本质,可以发现,当我们把标准输入文件给关闭并且打开了一个log.txt文件,通过上述现象明白,因为标准输入被关闭,所以log.txt这个文件对象的地址,此时就是存储在文件描述符表中下标为1的位置,然后最后通过打印发现,如果不把标准输入关闭,那么此时的打印结果,就是向标准输入文件中打印(也就是打印到我们的显示器上),但是如果,我们把标准输入给关闭(就是文件描述符表下标为1),此时可以发现,当我们再一次执行程序的时候,显示器上就不会再打印出我想要的内容,反而当我们查看被打开文件log.txt(也就是此时存储在文件描述符表中下标1处的文件对象地址)此时该文件中的内容是我想要打印的内容,这是为什么呢?所以上述的这一些奇奇怪怪的现象,我们就把它称为输出重定向,将本应该在标准输出(显示器)上输出的数据通过重定向的方式在别的文件中输出(log.txt) ,具体如下图所示:
一图搞定输出重定向:

结论: 我们无论是去调用系统调用接口还是调用库函数,本质上这些接口都不关心它是否是向标准输出文件中打印数据,它们只关心在文件描述符表中下标为1的位置处有没有文件对象的地址给它打印,到底向那个文件对象打印,它根本不在乎。
重定向原理:在上层无法感知的情况下,在操作系统内部,更改进程对应的文件描述符表中的下标中指针指向的地址
明白了上述输出重定向的原理,此时如下图所示,输入重定向也是同理的,本质就是将系统默认打开的标准输入、标准输出和标准错误文件关闭,然后按照文件描述符表的规律,让该下标拥有一个新的文件,此时通过这个文件进行读写步骤

并且我们通过输出重定向可以明白一个点,就是当我们需要将数据输出到标准输入或者某个下标为1的文件中时,这个文件每次都是会被清理的,导致我们每次写入的数据都是重新开始的,所以此时我们的追加重定向的原理,本质上就是将打来文件的方式给变换一下,从原来的 int fd = open(LOG,O_WRONLY | O_CREAT | O_TRUNC,0666); 变成 int fd = open(LOG,O_WRONLY | O_CREAT | O_APPEND,0666); 如这两句代码一样,只要把 O_TRUNC(清理)改成O_APPEND(追加),这样我们就从输出重定向,直接就变成了一个追加重定向了,所以输出重定向和追加重定向So,So!
总:无论是输出重定向还是追加重定向,它们都是想文件描述符表中下标为1中写入数据
北京时间:2023/3/27/23:22

几个月前,我读了一篇关于rubygem的博客文章,它可以通过阅读代码本身来确定编程语言。对于我的生活,我不记得博客或gem的名称。谷歌搜索“ruby编程语言猜测”及其变体也无济于事。有人碰巧知道相关gem的名称吗? 最佳答案 是这个吗:http://github.com/chrislo/sourceclassifier/tree/master 关于ruby-寻找通过阅读代码确定编程语言的rubygem?,我们在StackOverflow上找到一个类似的问题:
我想使用spawn(针对多个并发子进程)在Ruby中执行一个外部进程,并将标准输出或标准错误收集到一个字符串中,其方式类似于使用Python的子进程Popen.communicate()可以完成的操作。我尝试将:out/:err重定向到一个新的StringIO对象,但这会生成一个ArgumentError,并且临时重新定义$stdxxx会混淆子进程的输出。 最佳答案 如果你不喜欢popen,这是我的方法:r,w=IO.pipepid=Process.spawn(command,:out=>w,:err=>[:child,:out])
电脑0x0000001A蓝屏错误怎么U盘重装系统教学分享。有用户电脑开机之后遇到了系统蓝屏的情况。系统蓝屏问题很多时候都是系统bug,只有通过重装系统来进行解决。那么蓝屏问题如何通过U盘重装新系统来解决呢?来看看以下的详细操作方法教学吧。 准备工作: 1、U盘一个(尽量使用8G以上的U盘)。 2、一台正常联网可使用的电脑。 3、ghost或ISO系统镜像文件(Win10系统下载_Win10专业版_windows10正式版下载-系统之家)。 4、在本页面下载U盘启动盘制作工具:系统之家U盘启动工具。 U盘启动盘制作步骤: 注意:制作期间,U盘会被格式化,因此U盘中的重要文件请注
在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList()Obt
运行bundleinstall后出现此错误:Gem::Package::FormatError:nometadatafoundin/Users/jeanosorio/.rvm/gems/ruby-1.9.3-p286/cache/libv8-3.11.8.13-x86_64-darwin-12.gemAnerroroccurredwhileinstallinglibv8(3.11.8.13),andBundlercannotcontinue.Makesurethat`geminstalllibv8-v'3.11.8.13'`succeedsbeforebundling.我试试gemin
网络编程套接字网络编程基础知识理解源`IP`地址和目的`IP`地址理解源MAC地址和目的MAC地址认识端口号理解端口号和进程ID理解源端口号和目的端口号认识`TCP`协议认识`UDP`协议网络字节序socket编程接口`sockaddr``UDP`网络程序服务器端代码逻辑:需要用到的接口服务器端代码`udp`客户端代码逻辑`udp`客户端代码`TCP`网络程序服务器代码逻辑多个版本服务器单进程版本多进程版本多线程版本线程池版本服务器端代码客户端代码逻辑客户端代码TCP协议通讯流程TCP协议的客户端/服务器程序流程三次握手(建立连接)数据传输四次挥手(断开连接)TCP和UDP对比网络编程基础知识
目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称
最近在学习CAN,记录一下,也供大家参考交流。推荐几个我觉得很好的CAN学习,本文也是在看了他们的好文之后做的笔记首先是瑞萨的CAN入门,真的通透;秀!靠这篇我竟然2天理解了CAN协议!实战STM32F4CAN!原文链接:https://blog.csdn.net/XiaoXiaoPengBo/article/details/116206252CAN详解(小白教程)原文链接:https://blog.csdn.net/xwwwj/article/details/105372234一篇易懂的CAN通讯协议指南1一篇易懂的CAN通讯协议指南1-知乎(zhihu.com)视频推荐CAN总线个人知识总
深度学习部署:Windows安装pycocotools报错解决方法1.pycocotools库的简介2.pycocotools安装的坑3.解决办法更多Ai资讯:公主号AiCharm本系列是作者在跑一些深度学习实例时,遇到的各种各样的问题及解决办法,希望能够帮助到大家。ERROR:Commanderroredoutwithexitstatus1:'D:\Anaconda3\python.exe'-u-c'importsys,setuptools,tokenize;sys.argv[0]='"'"'C:\\Users\\46653\\AppData\\Local\\Temp\\pip-instal
需求:要创建虚拟机,就需要给他提供一个虚拟的磁盘,我们就在/opt目录下创建一个10G大小的raw格式的虚拟磁盘CentOS-7-x86_64.raw命令格式:qemu-imgcreate-f磁盘格式磁盘名称磁盘大小qemu-imgcreate-f磁盘格式-o?1.创建磁盘qemu-imgcreate-fraw/opt/CentOS-7-x86_64.raw10G执行效果#ls/opt/CentOS-7-x86_64.raw2.安装虚拟机使用virt-install命令,基于我们提供的系统镜像和虚拟磁盘来创建一个虚拟机,另外在创建虚拟机之前,提前打开vnc客户端,在创建虚拟机的时候,通过vnc