一、struct file内核对象
struct file是在内核中创建,专门用来管理被打开文件的结构体。struct file中包含了打开文件的所有属性,文件的操作方法集以及文件缓冲区(无论读写,我们都需要先将数据加载到文件缓冲区中。)等等。
我们在应用层进行数据的读写,本质是将内核缓冲区中的数据,进行来回拷贝。
二、文件描述符fd分配规则
1、进程默认打开0、1、2
我们可以直接使用0,1,2进行数据访问。
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<string.h>
int main()
{
char buf[1024];
ssize_t s = read(0, buf, 1024);
if(s > 0)
{
buf[s-1] = 0;//这样我们最后输入的那个回车(换行)就不会被打印
write(1,buf,strlen(buf));
// printf("%s\n",buf);
}
return 0;
}
运行程序后,程序等待我们输入:
随意输入字符:
按下回车:
程序执行完毕。
2、寻找最小&&未被使用的数据的位置,分配给指定的打开文件
验证:
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<string.h>
int main()
{
close(0);
int fd = open("test.txt",O_WRONLY | O_CREAT | O_TRUNC, 0666);
printf("fd:%d\n",fd);
close(fd);
return 0;
}
此时我们打开的这个test.txt文件,其fd就成了0:
三、重定向
1、输出重定向:
那么,如果我们close(1)呢?
(1)close(1)
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<string.h>
int main()
{
close(1);
int fd = open("log.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666);
if(fd < 0)
{
perror("open");
return 1;
}
printf("fd:%d\n",fd);
close(fd);
return 0;
}
可以看到,屏幕未输出任何东西,log.txt文件中也没有内容:
(2)fflush(stdout)
当我们刷新fflush(stdout)时:
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<string.h>
int main()
{
close(1);
int fd = open("log.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666);
if(fd < 0)
{
perror("open");
return 1;
}
printf("fd:%d\n",fd);
printf("stdout->%d\n",stdout->_fileno);
fflush(stdout);
close(fd);
return 0;
}
运行程序:
我们将其称为:输出重定向。
(3)总结:
上层并不知道我们将1号文件描述符的指向改变了,printf()打印的本质是向1号文件描述符里面打印,具体1号文件描述符指向的是显示器,就向显示器打印,指向的是文件,就向文件里打印。所以这里,printf()就向log.txt里面打印了。
重定向的 本质就是修改 文件描述符表 特定数组下标 里面的内容。
2、输入重定向:
我们首先向log.txt文件中写入数据:
我们首先close(0),然后再打开log.txt,这样log.txt的文件描述符fd就是0。
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<string.h>
int main()
{
close(0);
char buf[1024];
int fd = open("log.txt",O_RDONLY);
if(fd < 0)
{
perror("open");
return 1;
}
fread(buf,1,sizeof buf,stdin);
buf[strlen(buf)-1] = 0;//将"\n"符号改为0
printf("%s\n",buf);
return 0;
}
运行程序,我们可以看到,log.txt文件中的内容被打印出来了:
3、原理:
上层的fd不变,底层fd指向的内容在改变。
4、使用
我们这里使用dup2:
将oldfd的数组内容拷贝到newfd的数组内容中。
需要注意的是,这样就会导致有多个fd指向一个打开的文件,为了避免一个fd把文件关闭的时候,影响到其余的fd,在struct file中,存在一个f_count用来计数,有几个指针指向该文件,f_count就为几。
我们首先查看log.txt中的内容:
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<string.h>
int main()
{
int fd = open("log.txt",O_APPEND | O_WRONLY);
if(fd < 0)
{
perror("open");
return 1;
}
dup2(fd,1);
printf("haha\n");
fprintf(stdout,"yeye\n");
close(fd);
return 0;
}
然后执行程序:
可以看出文件内新增了内容。