哈尔滨多语言网站建设,wordpress插件的安装目录,亦庄网站开发公司,跨境电商开店平台文章目录 重定向缓冲区 正文开始前给大家推荐个网站#xff0c;前些天发现了一个巨牛的
人工智能学习网站#xff0c;
通俗易懂#xff0c;风趣幽默#xff0c;忍不住分享一下给大家。
点击跳转到网站。 重定向
内核中为了管理被打开的文件#xff0c;一定会存在描述一… 文章目录 重定向缓冲区 正文开始前给大家推荐个网站前些天发现了一个巨牛的
人工智能学习网站
通俗易懂风趣幽默忍不住分享一下给大家。
点击跳转到网站。 重定向
内核中为了管理被打开的文件一定会存在描述一个文件的file结构体这个结构体中大概有什么呢 我们知道文件文件内容 文件属性所以file结构体中一定会存在打开文件的各种属性其次它也一定存在自己的读写方法也就是方法集文件的内容是存在在磁盘中的所以file中又一个属于内核级别的文件缓冲区所以当我们读写文件的时候是需要把文件的内容拷贝到文件缓冲区中的然后如果读文件就把缓冲区中的内容拷贝到我们自己的定义的缓冲区中如果写或者修改的话就把内容拷贝到内核缓冲区中然后刷新到磁盘所以我们在应用层进行的数据读写的本质就是将内核缓冲区的内容进行来回拷贝。不管是读文件还是写文件都需要先把内容拷贝到文件缓冲区。
fd的分配规则 进程是默认打开了0,12文件描述符的我们在打开一个文件fd就是3如果我们关闭了1然后在进行打开文件那么新打开的文件fd就是1所以文件描述符的分配规则是遍历文件fd表寻找最小的没有被使用的位置然后分配给打开的文件。
重定向原理
重定向的就是把本来应该打印到显示器的内容打印了文件中而往显示器打印本质就是想显示器文件打印因为C语言中的标准输入输出本质就是封装了fd0和1所以我们利用文件描述符的分配规则就可以自己实现一个简单的重定向功能。 如果我们要实现一个输出重定向的话我们只需要把fd1关了然后再打开一个文件然后我们往显示器中打印内容就会往fd1中打印但是现在文件1指向的是我们自己新打开的文件。输入同理。
#include stdio.h
#include unistd.h
#include sys/types.h
#include sys/stat.h
#include fcntl.hint main()
{close(1);int fd open(log.txt,O_WRONLY | O_CREAT | O_TRUNC , 0666);if(fd 0) return -1;printf(hello printf\n);fflush(stdout);close(fd);return 0;
}所以通过这种方式我们就可以自己实现一个输出重定向。但是我们每次都要自己关闭1号文件描述符这样太麻烦了那么如果存在一种可以把我们打开的文件的fd内容覆盖1号下标的内容就可以实现这个技术所以重定向的本质就是修改文件描述符表。对于用户来说fd是不变的但是fd指向的内容改变了。系统中有一个函数dup2就可以实现这个功能。 dup2就可以让oldfd覆盖到newfd。对于被覆盖的文件OS会自动帮你关闭的所以我们通过这种方式也可以实现重定向功能。 以输入重定向为例 dup2(fd,0)就可以实现下图的效果。 所以重定向的本质就修改文件描述符指向的内容命令行级别的只需要对字符串进行特定的解析然后调用dup2函数就可以实现重定向功能。程序替换时不会影响重定向的因为程序替换只会替换代码和数据对于进程的PCB是不影响的所以对于PCB指向的文件fd
#include stdio.h
#include unistd.h
#include sys/types.h
#include sys/stat.h
#include fcntl.hint main()
{int fd open(log.txt,O_WRONLY | O_CREAT | O_TRUNC , 0666);if(fd 0) return -1;//使用dup2dup2(fd,1);printf(hello hello\n);close(fd);return 0;
}如果是对于追加和输入重定向的话我们只需要控制一些打开文件时打开的方式就可以实现和输出同理。
我们知道标准输入和标准输出是我们平时使用必不可少的东西所以系统会帮我们自动打开这都没毛病但是标准错误是什么东西
#include stdio.h
int main()
{printf(i am printf\n);perror(i am perror );return 0;
}如果我们直接运行 如果我们重定向一下 可以通过这种方式把标准输出和标准错误打印的东西分开打印perror和cerr都是向标准错误中打印我们可以通过重定向把标准输出和标准错误打印的东西分别打印到不同的文件方便调试。
打印到同一个文件 打印到不同文件
缓冲区
什么是缓冲区 缓冲区的本质就是一快内存用来存放数据的。
为什么要有缓冲区 缓冲区的主要作用就是提高效率谁使用缓冲区就提供谁的效率因为有缓冲区的存在我们在写一些东西的时候一定会涉及I/O操作就一定会访问硬件所以通过缓冲区累计一部分数据后再进行发送会远远比每次都进行I/O的效率要高很多。可以提高发送的效率。
缓冲区能够缓存一定的数据就一定会存在自己的刷新策略
全缓冲(缓冲区满了在进行刷新)行缓冲(行刷新)无缓冲(立即刷新)
这三种是一般的策略用户也可以通过fflush这样的函数来进行强制的刷新并且在进程结束的时候一般都要进行缓冲区的刷新的。一般对于显示器文件来说是行刷新对于普通的磁盘文件是全刷新的。
我们可以通过一个样例来证明一下这个缓冲区的存在
#include stdio.h
#include unistd.h
#include sys/types.h
#include string.hint main()
{printf(hello printf\n);fprintf(stdout, hello fprintf\n);fputs(hello fputs\n, stdout);char buffer[1024] hello write\n;write(1,buffer,strlen(buffer));pid_t id fork();return 0;
}这个代码很简单就不解释了我们先直接运行一下然后在重定向一下看结果 那么为什么会出现这个现象呢
当我们直接运行的时候我们调用的所有接口都是向显示器文件打印而显示器文件的刷新方式是行刷新而我们所有的打印后面都有‘\n’所以在fork()之前我们的数据都已经被刷新了包括write系统调用。当我们重定向的时候本质已经是向磁盘文件中打印了不是向显示器文件打印了所以刷新方式已经变成了全缓冲。全缓冲就意味着缓冲区很大当我们fork的时候我们实际写入的数据很少不足以把缓冲区打满所以当fork的时候数据仍然在缓冲区中。我们可以看到重定向之后只有C语言的接口打印了两次而write系统调用只打印了一次所以我们目前说的缓冲区是C语言提供的和操作系统没有任何关系。也侧面证明了exit和_exit的区别一个C语言提供的程序退出刷新缓冲区一个系统调用不刷新缓冲区所以这个缓冲区一定是C语言提供的。C/C提供的缓冲区里面保存的一定是我们用户的数据只要我们不刷新这个数据就属于我们用户但是如果我们把缓冲区的数据写入了OS中那么这部分数据就不属于我们了而是属于OS。当进程退出时一般都要刷新缓冲区即使没有达到刷新的条件。而刷新的本质即使清空缓冲区清空也是写入。所以当我们重定向向文件中打印的时候系统调用会先先打而C语言提供的接口打印的东西都还在C语言提供的缓冲区中当我们fork创建子进程后子进程会继承父进程的大部分数据当子进程或者父进程退出时退出的一方要刷新缓冲区也就是写入由于父子之间具有独立性就要发生写时拷贝这时就出现了上面C语言接口打印两次的情况。
我们之前说过文件也有自己的文件缓冲区也就是内核缓冲区所以C语言的缓冲区和内核缓冲区的关系就是我们平时先把数据拷贝到C语言的缓冲区根据刷新的机制在刷新到文件缓冲区然后OS根据自己的安排定时刷新到磁盘。所以文件读写的本质就是来回拷贝。 从用户缓冲区拷贝到文件缓冲区的过程就是我们平时说的刷新。 我们在使用C语言的I/O接口是都会接触FILE结构体就连默认打开的3个流都是FILE指针类型。 因此C语言提供的缓冲区就是在FILE结构体中。所以FILE中不仅封装了fd文件描述符还封装了缓冲区。