linux下文件操作

我们知道,在linux下,一切皆文件。那么要管理这些文件,就需要专门的文件操作。
下面的博客是对比文件IO和标准IO的文章文件IO和标准IO的区别

【文件描述符fd】
linux默认情况下会有三个打开的文件描述符:标准输入0、标准输出1,标准错误2。
我们知道,linux内核会为每一个进程分配一个task_struct结构体用来管理进程,其中包含管理文件的信息,操作系统用一个file结构体来描述目标文件。如下图:
这里写图片描述
每个打开的文件,在内核当中都有file对象,保存了文件相关的inode元信息。当我们打开一个文件时,需要将进程和该文件关联,每个进程都有一个*file的指针,指向一个file_struct结构体,而这个结构体中最主要的元素就是一个指针数组,其中每个元素都是一个指向打开文件的指针。所以,实际上,文件描述符就是该指针数组的下标,用来寻找对应的文件。
当我们用open多次打开同一个文件时,实际上每一次都打开的是独立的文件表,并不是共用同一份文件表。
这里写图片描述

而当一个进程用fork创建子进程之后,子进程继承了父进程的文件描述符表,此时,父子进程相同的文件描述符指向同一个文件表,但父子进程有各自的文件偏移量,当父子进程同时指向这个文件表时,文件表中的引用计数加一,当有其中一个进程关闭文件描述符时,引用计数减一,当引用计数减为0时,删除文件表。
这里写图片描述

【dup()和dup2()函数】

int dup(int oldfd);
int dup2(int oldfd,int newfd);

dup()和dup2()的作用都是用来复制一个文件描述符,它们经常用来重定向进程的stdin,stdout,stderr.

dup()
利用dup(),我们可以复制一个文件描述符。传给该函数一个已有的文件描述符,它就会返回一个新的文件描述符,这个新的文件描述符是传给它的描述符的拷贝。即两个文件描述符共享同一个数据结构,例如,如果我们对一个文件描述符执行lseek操作,得到的第一个文件的位置和第二个是一样的。

dup2()
dup2函数跟dup函数相似,但dup2函数允许调用者规定一个有效描述符和目标描述符的id。dup2函数成功返回时,目标描述符(dup2函数的第二个参数)将变成源描述符(dup2函数的第一个参数)的复制品,换句话说,两个文件描述符现在都指向同一个文件,并且是函数第一个参数指向的文件。

int oldfd;
oldfd=open("log.txt",O_RDWR|O_CREAT,0644);
dup2(oldfd,1);
close(oldfd);

我们打开了一个新文件,称为“log.txt”,并收到一个文件描述符,该描述符叫做fd1。我们调用dup2函数,参数为oldfd和1,这会导致用我们新打开的文件描述符替换掉由1代表的文件描述符(即stdout,因为标准输出文件的id为1)。任何写到stdout的东西,现在都将改为写入名为“log.txt”的文件中。需要注意的是,dup2函数在复制了oldfd之后,会立即将其关闭,但不会关掉新近打开的文件描述符,因为文件描述符1现在也指向它。
这里写图片描述 在这段代码中,我们首先创建一个管道,然后fork出一个子进程,在进程中,我们首先关闭stdout,然后利用dup2让输出重定向到管道的fds[1]中,然后关闭管道的输入端,用execlp进程替换函数把子进程进程映像替换为ls -l. 父进程担任管道的接收端,我们关闭父进程的stdin,然后用dup2输入重定向到fds[0],关闭管道的fds[1],最后通过execlp将父进程的进程映像替换为wc -l.

相关文章
相关标签/搜索