重定向理解
在Linux下,当打开一个文件时,进程会遍历文件描述符表,找到当前没有被使用的 最小的一个下标,作为新的文件描述符。
代码验证:
①:先关闭下标为0的文件,在打开一个文件,此时该文件的fd为0
#include<stdio.h>#include<sys/types.h>#include<fcntl.h>#include<string.h>#include<unistd.h>int main(){//提前关闭下标为0的文件close(0);int fd=open("log.txt",O_WRONLY|O_CREAT|O_TRUNC,0666);if(fd<0){perror("open");return 1;}printf("log.txt打开成功:fd:%d\n",fd); close(fd);return 0;}
②:关闭下标为1的文件,在打开一个新的文件,再用 printf 打印一段信息
#include<stdio.h>#include<sys/types.h>#include<fcntl.h>#include<string.h>#include<unistd.h>int main(){//提前关闭下标为1的文件close(1);int fd=open("log.txt",O_WRONLY|O_CREAT|O_TRUNC,0666);if(fd<0){perror("open");return 1;}printf("log.txt打开成功:fd:%d\n",fd);fflush(stdout); close(fd);return 0;}
出现的问题:
1.printf输出的内容没有出现在显示器上
2.应该在显示器上出现的信息却被加载到了文件中
【解释】:
在上述代码中,我们先关闭了下标为1的文件,在操作系统中该文件对应的是标准输出(显示器),而我们打开文件后,会将下标1作为该文件的描述符,printf函数的作用就是向下标为1的文件中写入信息,但是此时下标1对应的不在是标准输出了,对应的是我们打开的文件,但是上层仍认为1号下标对应的就是显示器,所以向1号下标文件写入就相当于向文件写入,而这个现象就称之为重定向,其本质是在内核中改变文件描述符表特定下标的内容,与上层无关
系统调用函数 dup2
该函数的功能是将文件描述符oldfd所对应文件内容拷贝给newfd对应文件
#include <unistd.h>
int dup2(int oldfd, int newfd);
举例:
#include<stdio.h>#include<sys/types.h>#include<fcntl.h>#include<string.h>#include<unistd.h>int main(){int fd=open("log.txt",O_WRONLY|O_CREAT|O_TRUNC,0666);if(fd<0){perror("open");return 1;}dup2(fd,1);printf("hello Linux\n");printf("hello Linux\n");printf("hello Linux\n"); fflush(stdout);close(fd);return 0;}
缓冲区理解
如果将上述代码中的 fflush(stdout) 删除的话,应该向文件写入的信息又写不进去了,这又是为什么呢?程序结束不是会自动刷新缓冲区吗?信息去哪里了?
【解释】:
在c语言中,为了用户使用方便,封装了三个结构体,stdout、stdin、stderr,这三个结构体中除了封装了文件描述符外,还存在着语言级别的文件缓冲区
在[Linux]基础IO(上)--理解文件系统调用、文件描述符、万物皆文件一文中我们谈到,每一个文件的struct file都存在一个内核级的文件缓冲区,printf输出的内容会先保存在语言级别的那个缓冲区中,C语言在通过文件描述符将该缓冲区的内容加载到内核级别的文件缓冲区中,操作系统在刷新到外设
此时,程序中printf输出的内容就保存在语言级别的文件缓冲区中,虽然程序结束时会自动刷新缓冲区,但是在程序结束前,我们就已经将文件关闭了,就无法向文件中写入信息了,当程序结束时,这部分数据就丢失了
缓冲区刷新策略
1.立即刷新:fflush(stdout) int fsync(int fd)
2.行刷新:写满一行就刷新(显示屏)
3.全刷新:当缓冲区写满才刷新
4.特殊情况:程序结束强制刷新
缓冲区的意义:
- 解耦:对于语言级别的文件缓冲区,只需要想怎样将数据导入缓冲中,不需要管语言怎么再将数据导入内核级文件缓冲区,对于内核级文件缓冲区,将数据导入进来后,就不需要管操作系统怎样将数据刷新到外设中了
- 提高效率:系统调用是有一定的成本的,当缓冲区写满或者写完一行时,再调用系统接口,一次或多次的将内容进行处理,这样可以极大减少系统调用的次数,不仅可以提高IO速率,也可以提高用户的使用效率