1.文件描述符、文件句柄和打开文件之间的关系

专栏说明

  两三个月前试着读过这本书,感觉像啃石头。今天终于又下定决心来啃它,体验比之前好多了。
  但是书里的东西,还是比较抽象,一下子看不明白,所以准备对学习过程做个记录。

这是第一篇,以后再碰到难点会继续记录。

起因

p76~p79
76、77草草看过去,不甚求解,只记得p78的一条要点:

两个不同的文件描述符,若指向同一打开文件句柄,将共享同一文件偏移量。因此,如果通过其中一个描述符来修改文件偏移量(由调用read()、write()、或lseek()所致),那么从另一文件描述符中也会观察到这一变化。无论这两个文件描述符分属于不同进程,还是同属于一个进程,情况都是如此。

但是78页又讲到:

仅仅简单地打开results.log文件来两次是远远不够的(第一次在描述符1上打开,第二次在描述符2上打开)。首先两个文件描述符不能共享相同的文件偏移量指针,因此有可能相互覆盖彼此的输出。在这打开的文件不一定就是磁盘文件。

经过

刚看到挺懵逼的。😦
又从头看了一遍,才发现了重点:

  • 进程级的文件描述符表(文件描述符)
  • 系统级的打开文件表(文件句柄)
  • 文件系统的i-node表
    这三个东西不是一回事。

看懂这张图很重要
PICTURE:/home/sixqaq/.config/tencent-qq/1065236069/image/origin/43845E7404A5613B169B3E7AB15A6CCB.jpg
区别在于书上那段话:

   在进程A中,文件描述符1和20都指向同一个打开的文件句柄(标号为23)。这可能是通过调用dup()、dup2()或fcntl()而形成的(参见5.5节)。
  进程A的文件描述符2和进程B的文件描述符2都指向同一个打开的文件句柄(标号73)。这种情形可能在调用fork()后出现(即,进程A与进程B之间是父子关系),或者当某进程通过UNIX域套接字将一个打开的文件描述符传递给另一个进程时,也会发生(参见61.13.3节)。
  此外,进程A的描述符0和进程B的描述符3分别指向不同的打开文件句柄,但这些句柄均指向i-node表中的相同条目(1976),换言之,指向同一文件。发生这种情况是因为每个进程各自对同一文件发起了open()调用。同一个进程两次打开同一文件也会发生类似情况。

结果

看到这里才明白,总之就是三条规则:

  1. 指向同一文件句柄的文件描述符共享同一文件偏移量(必定也指向同一个i-node条目,也即是同一文件)。
  2. open()两次打开的描述符不指向同一文件句柄(也就是文件偏移量不相同)。
  3. dup()、dup2()复制的文件描述符指向同一文件句柄(也就是文件偏移量相同)。

示例

cat tmp.txt

123456789ABCDEFGHIJKLMN

dup()

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main(void)
{
    const char fileName[]="tmp.txt";

    int fd_1 = open(fileName, O_RDONLY),
        fd_2 = dup(fd_1);//copy the fd_1 by dup()
    char buf [1024];

    ssize_t numRead;
    numRead = read(fd_1, buf, 10);
    buf[numRead]='';
    printf("numRead: %zdn",numRead );
    printf("%sn", buf);

    numRead = read(fd_2, buf, 10);
    buf[numRead]='';
    printf("numRead: %zdn", numRead);
    printf("%sn", buf);
	
    printf("fd_1:%dn", close(fd_1));
    printf("fd_2:%dn", close(fd_2));

}
result:
	numRead: 10
	123456789A
	numRead: 10
	BCDEFGHIJK
	fd_1:0
	fd_2:0

open()

	.../*same as above*/
		
    int fd_1 = open(fileName, O_RDONLY),
        fd_2 = open(fileName, O_RDONLY);
				//reopen the file

	.../*same as above*/
result:
	numRead: 10
	123456789A
	numRead: 10
	123456789A
	fd_1:0
	fd_2:0

初学者,如有理解错误之处,还望大佬多多指正。😃

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>