关于文件描述符fd以及文件指针

linux中的操作都是通过文件描述符来进行的

1 文件描述符

在Linux系统中打开或创建文件就会有一个文件描述符,它是一个很小的整数。
Linux中默认文件描述符的上限是1024,可通过命令ulimit -n来查看,也可ulinit -n 65535重置上限大小

2 文件描述符本质是进程表项数组的下标

2.1 进程表、文件表与v节点表(i节点表)

这里引用一张经典的图片,文件描述符fd就是进程表项的下标。
进程打开文件
可以从右往左看

  1. V节点表
    v节点表也叫作i节点表,在整个系统中只有一张,可以看做是一个结构体的数组,该数组的一个元素对应物理磁盘的一个文件
  2. 文件表
    文件表在整个系统中也只有一张,也是一个结构体数组,但是该结构体有三个比较重要的字段
    • 文件状态标志
      这个标志是指文件是用来读还是写操作的,open文件的时候第二个参数就是这个
    • 当前文件位移量
      位移记录文件当前的读写位置,是一个指针。
    • v节点指针
      该指针指向全局位移的v节点表中的某一项,从而和具体文件相关联
  3. 进程表/文件描述符表
    进程表也叫文件描述符表,每个进程在PCB(Process Control Block)中保存着一份文件描述符表,每个进程只有一张
    文件描述符表可看做是一个数组指针,每个指针指向一个文件表中的一个元素,从而和一个具体的物理文件关联起来。
    所以我们可以看到,通过一个文件描述符fd,可以找到一个文件表项,而一个文件表项又可关联一个物理文件,这样fd就关联了具体文件。

2.2 进程fork对文件描述符的影响

进程fork后子进程也会继承父进程的文件描述符表,这样的话父子进程会有公共的文件描述符fd项以及同一份文件表项,于是二者可能会同时操作同一个文件,且偏移值相互影响。
如果是两个进程独立open同一个物理文件,那么会有两份对应的fd+文件表项,在读的时候不会影响。
因此子进程不用父进程打开的文件时,在调用后应该将fd关闭

3 文件描述符与文件指针

首先文件描述符fd是下标,但是对应的文件描述符表的值是指针。
C 语言中使用文件指针做为 I/O的句柄。文件指针指向进程用户区中的一个被称为 FILE 结构的数据结构。FILE 结构包括一个缓冲区和一个文件描述符。而文件描述符是文件描述符表的一个索引,因此从某种意义上说文件指针就是句柄的句柄(在Windows系统上,文件描述符被称作文件句柄。
二者其实是可以相互转化的。

fd–>FILE*

1
2
3
函数 fileno
int _fileno( FILE *stream );
fileno 用来取得参数stream指定的文件流所使用的文件描述符。

FILE* –>fd

1
2
FILE* fdopen(int fd, const char* type);
fdopen 取一个现存的文件描述符,并使一个标准的I/O流与该描述符相结合