Linux系统之----重定向
1.文件描述符和文件结构体
前文我们已经了解了文件描述符,回顾一下,文件描述符是一个非负整数,用于标识一个打开的文件。在Linux系统中,文件描述符是一个整数,通常使用int
类型来表示。每个进程都有一个文件描述符表(files_struct),用于存储该进程打开的所有文件的描述符。文件描述符表中的每个条目都指向一个struct file
结构体,该结构体包含了文件的详细信息。
现在我们在介绍一下struct file:
struct file
是一个结构体,用于描述一个打开的文件。它包含了文件的各种信息,如文件类型(标准输入、标准输出、标准错误或普通文件)、文件偏移量等。struct file
中有一个指针f_inode
,指向文件的inode结构体,inode包含了文件的元数据(如文件大小、权限等)。
最终我们总结一下文件操作,在Linux系统中,所有文件操作(如读写)都是通过文件描述符进行的。操作系统通过文件描述符来识别和管理文件。
2.文件读写操作
2.1 文件读写的本质
文件读写操作实际上是对文件内核缓冲区的操作。内核缓冲区是操作系统为文件分配的内存区域,用于暂存文件数据。read
和write
函数并不是直接对磁盘文件进行操作,而是对文件内核缓冲区进行操作。所以,write根本就不是写入到文件,wite本质是拷贝函数!把数据从用户空间拷贝到对应文件的内核缓冲区中!不仅仅是写,我们进行的任何文件内容的增删查改,都必须把文件的内容提前预加载到该文件的文件内核缓冲区中!
2.2 文件内容和属性
文件由内容和属性组成。内容是文件的实际数据,属性包括文件的大小、权限等元数据。文件内核缓冲区中保存了文件的内容,而文件属性则保存在磁盘上的文件系统中。
2.3 文件操作的内部机制
当我们对文件进行读写操作时,实际上是在操作文件内核缓冲区。操作系统会在适当的时候将缓冲区中的数据写入磁盘,而什么时候写入到磁盘文件,由OS自己决定时机来进行刷新。文件描述符表中的struct file
结构体包含了文件的内核缓冲区信息,通过这些信息,操作系统可以管理和操作文件。
附上老师的板书:
3. 文件描述符的分配规则
我们先看几组代码
代码组1:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{ int fd = open("myfile", O_RDONLY); if(fd < 0){ perror("open"); return 1; } printf("fd: %d\n", fd); close(fd); return 0;
}
运行并执行,发现结果直接是3
代码组2:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{ close(2);int fd = open("myfile", O_RDONLY); if(fd < 0){ perror("open"); return 1; } printf("fd: %d\n", fd); close(fd); return 0;
}
当我们关掉文件操作符号2时,发现fd的文件操作符变为了2
代码组3:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{ close(0);int fd = open("myfile", O_RDONLY); if(fd < 0){ perror("open"); return 1; } printf("fd: %d\n", fd); close(fd); return 0;
}
当我们关掉文件操作符号0时,发现fd的文件操作符变为了0
由此,我们可以推断出在files_struct数组当中,找到当前没有被使⽤的最小的一个下标,作为新的文件描述符。
4.重定向
上述例子中,倘若我要是close(1)呢?我们试一下
惊奇的发现没有结果输出了,原因就是1所对应的是stdout,stdout是向屏幕显示器文件输出,你给他关了他往哪输出去? 但是我们真的查看不到了吗?实际上结果被写到了myfile文件里面,不信自己试一下:

那么,重定向本质是什么?
4.1 重定向本质
重定向的本质是改变进程的标准输入(stdin)、标准输出(stdout)和标准错误(stderr)的默认流向。在Unix/Linux系统中,默认情况下,这些流分别对应终端输入、终端显示和终端错误显示。通过重定向我们可以将这些流改向到文件或其他命令,从而实现数据的灵活处理和错误信息的记录。
4.1.2 dup2
我们先查一下他
出来一堆乱糟糟的东西看不懂思密达。。。。。
好下面是对其的解释:
说人话就是:
dup2
是一个在 Unix 和 Linux 系统中用于复制文件描述符的系统调用。它的作用是将一个已经打开的文件描述符复制到另一个文件描述符上,同时可以选择性地关闭目标文件描述符上原有的文件。
参数说明:
oldfd
:要复制的原始文件描述符。
newfd
:目标文件描述符。如果该文件描述符已经打开,它会被关闭,然后被复制。
返回值
成功时返回新的文件描述符(通常与 newfd
相同)。失败时返回 -1,并设置 errno
以指示错误原因。
代码示例:
在示例之前,我们先看一个函数read,生词挺少的这里我就不翻译了~!
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main()
{ int fd = open("./log", O_CREAT | O_RDWR); if (fd < 0){ perror("open"); return 1; } close(1); dup2(fd, 1);for (;;) { char buf[1024] = {0}; ssize_t read_size = read(0, buf, sizeof(buf) - 1); if (read_size < 0) { perror("read"); break; }printf("%s", buf); fflush(stdout); }return 0;
}
本篇文章到此为止!!