#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> #include <stdlib.h> #include <string.h> int main(void){ int fd=0; fd=open("./file.txt",O_RDWR); if(-1 == fd){ fprintf(stderr, "%s\n",strerror(errno)); exit(1); } printf("open ok\n"); char buf1[]="hello word"; write(fd,buf1,strlen(buf1)); lseek(fd,SEEK_SET,0); char buf2[30]={0}; read(fd,buf2,sizeof(buf2)); close(fd); printf("buf2=%s\n",buf2 ); }
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int open(const char *pathname, int flags); int open(const char *pathname, int flags, mode_t mode);
open函數
a.利用文件名,通過文件系統找到塊設備(磁盤,U盤等)上的文件
文件系統就是程序代碼,組織管理塊設備上的所有文件
文件系統屬於OS的一部分
b.找到文件后,調用塊設備驅動程序,打開文件
驅動程序也是os的一部分
open打開成功后,open做了哪些事情
1.記錄打開文件的信息
a.程序運行起來后就是一個進程,OS會創建一個task_struct結構體,記錄程序運行時的各種信息,
比如所打開文件的相關信息
b.open將文件成功打開后,在task_struct中又會創建一些結構體(數據結構),
用於記錄當前進程目前所打開的文件信息,后續所有的文件操作,都需要依賴於這些信息,
其中包括指向打開文件的文件描述符
2.open函數會聲請一段內存空間(內核緩存),后續讀寫文件時,用於臨時緩存讀寫文件時的數據
a.緩存:
即開辟的一段內存空間,比如char buf[100]就是一段100字節的緩存空間,用於臨時存放中轉的數據
b.內核緩存與應用緩存:
open是OS所提供的新系統函數,屬於OS內核的一部分,所以open函數開辟的緩存空間就是內核緩存
比如代碼里buf1和buf2是應用程序定義的,因此叫應用緩存
其實定義的一切變量空間,比如 Int a,int b[10] 都是緩存,用於臨時緩存數據
c.open為什么要開辟內核緩存空間
內核讀寫速度>磁盤讀寫速度,有了在內存中開辟的內核緩存后,上層讀寫數據時,會直接讀寫緩存,速度會很快,
至於緩存與磁盤文件數據的交換,就留給下層去做,這樣可以節省上層操作的時間
d.注意:open時只是開辟了內核緩存空間,里面並沒有數據,只有當進行讀寫時,才會緩存讀寫數據
e.緩存數據的流動
寫:應用緩存->open函數->寫到內核緩存--->驅動程序(驅動緩存)->磁盤上
讀:磁盤->驅動緩存->內核緩存->應用緩存->打印輸出
open函數
man 2 open
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags);
功能:只能打開已經存在的文件,如果不存在就返回-1 報錯
int open(const char *pathname, int flags, mode_t mode);
功能:如果文件存在就直接打開,不存在就按照指定的文件權限,創建指定名字的新文件
三個參數時,可以打開已存在的文件和文件不存在時創建文件
open返回值:
成功返回一個非負整數的文件描述符
失敗返回-1,並且設置錯誤號給系統定義的全局變量errno,用於標記函數到底出了什么錯
flags參數:model,創建文件時,用於指定文件的原始權限,就是rwxrwxr--
flags:O_RDONLY,O_WRONLY,O_RDWR,O_TRUNC,O_APPEND
指定打開文件的方式,這些宏可以使用|組合,可同時指定多個
宏的含義
a. O_RDONLY 只讀方式打開,只能對文件進行讀
b. O_WRONLY 只寫方式打開,只能對文件進行寫
c. O_RDWR 可讀可寫方式打開文件
以上三個在指定時,只能唯一指定,不可以組合,比如O_RDONLY|O_WRONLY
d. O_TRUNC:打開時將文件內容清0
e. O_APPEND: 打開文件后,追加新數據到文件末尾
不指定這個選項的話,新寫入的數據會從頭開始寫,覆蓋原有數據
f. O_NONBLOCK,O_ASYNC
a,b,c不可以組合,但可以和def組合
g. O_CREAT
指定時,文件存在,直接打開
文件不存在,創建該名字的文件
指定此參數時,需要設置第三個參數,用於指定新打開文件的原始權限
h. O_EXCL
當O_EXCL與O_CREAT同時被指定,打開文件時,如果文件存在,就報錯
單獨指定沒有意義,需和O_CREAT配合使用
意義:保證每次open的是一個新文件,如果文件之前就存在,提醒打開的不是一個新文件
保證檢查文件的存在和創建文件是原子操作。
對於打開軟鏈接,不加O_EXCL會在指向的位置創建文件,加上O_EXCL可禁止在指向位置創建文件,調用失敗,避免特權應用在系統目錄下創建文件,消除安全隱患
文件描述符
open成功就會返回一個非負整數(0,1,2,3 ....)的文件描述符,
文件描述符指向打開的文件,后續的read/write/close等函數的文件操作,都是通過文件描述符來實現
文件描述符池
每個程序運行起來后,就是一個進程,系統會給每個進程分配0~1023的文件描述符范圍,
每個進程打開文件時,open所返回的文件描述符是0~1023范圍中的某個數字
0~1023 這個范圍,就是文件描述符池
1023這個上限可以修改,但已經夠用,一個進程同時打開1023個文件的情況很少見,所以一般很少改
open返回文件描述符的規則:返回當前最小沒用的那個
進程一運行起來,0,1,2已經被使用了,最小沒被用的是3,所以返回3
如果又打開了一個文件,最小沒被用的應該是4
文件關閉后,被文件用的描述符會被釋放,等着下一次open時被重復利用
下面的2次均為3
#include <fcntl.h> #include <stdio.h> #include <errno.h> #include <sys/types.h> #include <sys/stat.h>
int main(int argc,char *argv[]){ int fd=open("./1.txt",O_RDWR|O_CREAT,0664); if(fd<0){ fprintf(stderr, "err:%s\n",strerror(errno)); }else{ printf("fd=%d\n",fd ); } close(fd); fd=open("./11.txt",O_RDWR|O_CREAT,0664); if(fd<0){ fprintf(stderr, "err:%s\n",strerror(errno)); }else{ printf("--fd=%d\n",fd ); } close(fd); return 0; }
open文件描述符與fopen文件指針關系
1.open:linux的系統函數(文件Io函數)
man 2 open
open成功后,返回的文件描述符,指向打開的文件
2.fopen: c庫的標准io函數
man 3 fopen
#include <stdio.h>
FILE *fopen(const char *path, const char *mode);
fopen成功后,返回的是FILE *的文件指針,指向了打開的文件
3.對於linux的c庫來說,fopen這個c庫函數,最終其實還是open函數來打開文件的
fopen只是對open這個函數的二次封裝
應用程序->FILE * fopen標准io函數(c庫函數)->int open文件io函數(linux系統函數)
fopen的文件指針,最終還是會被替換成open的文件描述符,然后用於操作打開的文件