#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
using namespace std;
FILE *f = fopen("/home/ubuntu/3.txt","w+"); //open file , read and write, everytime truncate file
FILE *f1 = fopen("/home/ubuntu/3.txt","r"); //open file , read and write, everytime truncate file'
int fd = open("/home/ubuntu/3.txt",O_RDONLY);
int fd1 = open("/home/ubuntu/3.txt",O_RDONLY);
int i = setvbuf(f,NULL,_IONBF,0); //no buff write , make sure data will be synced into file in time
int main()
{
char inbuf[100] = {0};
char outbuf[100] = {0};
char i = '0';
long j = 0;
if(fd == fd1){
cout<< " same " << endl;
}else{
cout<< " not same " << endl;
}
while(i < '9'){
memset(inbuf,0,sizeof(inbuf));
memset(outbuf,0,sizeof(outbuf));
inbuf[0] = i;
fwrite(inbuf,1,1,f);
cout<< " write : " << inbuf[0];
int pos = ftell(f);
cout << " curr : " << pos;
//fseek(f,j,SEEK_SET); //both fwrite and fread will change offset, so reseek before do fread
fseek(f1,j,SEEK_SET); //if 2nd time open , fseek(f,j,SEEK_SET) will not affect f1's offset , so fseek f1
fread(outbuf,1,1,f1);
cout<< " read : " << outbuf[0] << endl;
i++;
j++;
}
return 0;
}
每个进程都有一个叫做进程表项的数据结构,里面包含了当前进程打开的所有文件的文件描述符,每个文件描述符都关联一个叫做文件指针的指针成员,这个指针指向一个叫做文件表项的数据结构,这个数据结构里包含文件状态标志(读/写/追加/同步/非阻塞等等),当前文件偏移量,v节点指针。v节点指针指向文件系统的v节点表项,v节点表项是文件系统级别的数据结构,所有进程所有线程都共享,里面存储着文件内部的实际数据。
当两个进程都打开同一个文件时,会产生两个互不关联但可能值相等的 fd / FILE* :
- 每个 fd / FILE* 记录不同的 close_on_exec 标志;
- 每个 fd / FILE* 持有不同的文件偏移量信息;
- 每个 fd / FILE* 拥有不同的文件状态标志;
- 每个 fd / FILE* 指向相同的v节点表项。
当一个进程两次打开同一个文件时,会产生两个互斥且值不可能相等的 fd / FILE* :
- 每个fd或FILE* 记录不同的 close_on_exec标志;
- 每个 fd / FILE* 持有不同的文件偏移量信息;
- 每个 fd / FILE* 拥有不同的文件状态标志;
- 每个 fd / FILE* 指向相同的v节点表项。
dup && dup2
前面说到每个fd / FILE* 都会由各自的数据结构(除v节点表项),但是也有一个例外,就是用dup 和 dup2来复制文件描述符,dup和dup2会新建一个文件描述符,但是这个文件描述符和原文件描述符共享文件表,即共享 文件状态标志,当前文件偏移量 ,v节点指针。但是close_on_exec标志是新的,因为这个标志存在于文件描述符表中。
dup和dup2不可以跨进程进行文件描述符复制,因为每个进程的文件描述符表项是完全独立的。
边读边写:
边读边写时需要明确当前读写的 fd / FILE* 对应的当前文件偏移量是什么:
- 同一个进程场景下,读写作用于相同的 fd / FILE* ,那么读写的文件偏移量是共享的。
- 同一个进程场景下,读写作用于不同的 fd / FILE* (多次打开同一个文件获得不同的fd / FILE* ), 那么读写的文件偏移量是独立的,这个时候要自行处理,如果还是多线程的,那么还需要对存储偏移量的变量加锁。有个例外,指定 O_APPEND / "a+" 时,操作系统会保证每次读写都使用当前文件偏移量的尾部,但是需要注意的是这个标志存储在文件状态标志中,因此当dup/dup2的时候会出现不同 fd / FILE* 共享文件状态标志的情况。
- 同一个进程场景下,读写由 dup / dup2 创建的 fd / FILE* ,这个时候和1)一样是共享偏移量的。