基礎IO
- C語言檔案操作函式匯總
- 默認打開的3個輸入輸出流
- 系統IO
- open函式
- open的頭檔案
- open函式的第一個引數
- open函式的第二個引數
- open函式的第三個引數
- open函式的回傳值
- 檔案描述符
- 檔案描述符的規則
- 重定向
- 重定向的本質
- dup2函式
- FILE
C語言檔案操作函式匯總
下面是C語言的檔案操作函式的介面:

對檔案進行寫入操作:
1 #include<stdio.h>
2
3 int main()
4 {
5 FILE* fp =fopen("t.txt","w");
6 if(fp == NULL)
7 {
8 perror("fopen fail\n");
9 return 1;
10 }
11
12 fputs("亞索\n",fp);
13 fclose(fp);
14 return 0;
15 }
cat 看一下就已經寫入成功了,

對檔案讀取操作:
1 #include<stdio.h>
2
3 int main()
4 {
5 FILE* fp =fopen("t.txt","r");
6 if(fp == NULL)
7 {
8 perror("fopen fail\n");
9 return 1;
10 }
11 char buffer[64];
12 fgets(buffer,sizeof(buffer),fp);
13 printf("%s",buffer);
14 fclose(fp);
15 return 0;
16 }
運行程式:剛剛寫入的就讀取并列印在顯示幕上了,

C的檔案操作就簡單使用一下,后面會補上關于檔案操作的,
默認打開的3個輸入輸出流
行程在運行的時候都會打開默認打開3個輸入輸出流,分別是標準輸入流,標準輸出流,標準錯誤流,對應到C語言中就是stdin,stdout,stderr,stdin對應的設備是鍵盤,stdout和stderr對應的設備是顯示幕,
查看man手冊我們課題看到這3個都是FILE*

所以當C程式被運行起來,OS就會打開這3個輸入輸出流,我們就可以呼叫printf類似的函式對顯示幕和鍵盤進行對用的輸入輸出的操作了,
系統IO
操作檔案除了語言提供的介面,我們還可以使用系統呼叫介面,上面的C語言中的檔案介面函式叫庫函式,在前面的講系統時畫的一張圖:

C的庫函式就是對系統呼叫進行封裝,方便二次開發,
open函式
open的函式原型:
int open(const char *pathname, int flags, mode_t mode);
open的頭檔案
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
open函式的第一個引數
pathname:要打開或創建的目標檔案
當pathname以路徑的方式給出,則但需要創建檔案時在pathname路徑下進行創建
若是以檔案名方式給出,則但需要創建檔案時,默認在當前路徑,
open函式的第二個引數
flags: 打開檔案時,可以傳入多個引數選項,用下面的一個或者多個常量進行“或”運算,構flags,
常用的選項:
O_RDONLY: 只讀打開
O_WRONLY: 只寫打開
O_RDWR : 讀,寫打開
這三個常量,必須指定一個且只能指定一個
O_CREAT : 若檔案不存在,則創建它,需要使用mode選項,來指明新檔案的訪問權限
O_APPEND: 追加寫
打開檔案時可以傳入多個引數,可以用“ | ”隔開,
例如:用只寫的方式打開檔案當檔案不存在時
O_WRONLY | O_CREAT
open函式的第三個引數
mode:表示創建檔案的默認權限
但實際上創建出來的檔案還會受到umask的影響,實際創建的檔案權限為:mode&(~umask),umask的默認值一般是0002.若想不受影響,則需要在創建檔案前將umask的值設為0
umask(0)
open函式的回傳值

我們來列印看看檔案描述符:
1 #include<stdio.h>
2 #include <sys/types.h>
3 #include <sys/stat.h>
4 #include <fcntl.h>
5
6
7 int main()
8 {
9
10 umask(0);
11 int fd1 = open("g.txt1",O_RDONLY | O_CREAT,0666);
12 int fd2 = open("g.txt2",O_RDONLY | O_CREAT,0666);
13 int fd3 = open("g.txt3",O_RDONLY | O_CREAT,0666);
14 int fd4 = open("g.txt4",O_RDONLY | O_CREAT,0666);
15 printf("fd1:%d\n",fd1);
16 printf("fd2:%d\n",fd2);
17 printf("fd3:%d\n",fd3);
18 printf("fd4:%d\n",fd4);
19 return 0;
20 }

如果打開一個不存在的檔案呢?
1 #include<stdio.h>
2 #include <sys/types.h>
3 #include <sys/stat.h>
4 #include <fcntl.h>
5
6 int main()
7 {
8 int fd = open("x.txt",O_RDONLY);
9 printf("fd:%d\n",fd);
10
11 return 0;
12 }
運行直接是回傳-1.

檔案描述符
檔案是由行程運行時打開的,一個行程可以打開多個檔案,在系統中可能存在大量的行程,那系統中也存在很多檔案,為了區分已經打開的檔案屬于哪個特定的行程,所以還要建立行程和檔案的對應關系,

當檔案加載到記憶體時,系統會創建struct flie,并用雙鏈表連接起來,同時還有file_struct,而file_struct中放的是結構體指標陣列,每個每個行程都有一個指標file*,指向file_struct.Linux行程默認情況下會有3個預設打開的檔案描述符,分別是標準輸入0, 標準輸出1, 標準錯誤2. 0,1,2對應的物理設備一般是:鍵盤,顯示幕,顯示幕,從3開始指向新的檔案,所以本質上檔案描述符就是該陣列的下標,因此,只要拿著檔案描述符就可以找到對應的檔案,
檔案描述符的規則
1 #include<stdio.h>
2 #include <sys/types.h>
3 #include <sys/stat.h>
4 #include <fcntl.h>
5 #include<unistd.h>
6
7 int main()
8 {
9 int fd = open("t.txt",O_RDONLY);
10 if(fd < 0)
11 {
12 perror("open");
13 return 1;
14 }
15
16 printf("fd:%d\n",fd);
17 close(fd);
18 return 0;
19 }

先關閉0
close(0)

//關閉2試試
close(2);

綜上可以得出結果:檔案描述符的規則在file_struct陣列中找到當前沒有被使用的最小的一個下標,作為新的檔案描述符,
重定向
先來一段代碼:
2 #include <sys/types.h>
3 #include <sys/stat.h>
4 #include <fcntl.h>
5 #include<unistd.h>
6
7 int main()
8 {
9 close(1);
10 int fd = open("p.txt",O_WRONLY|O_CREAT,00644);
11 if(fd < 0)
12 {
13 perror("open");
14 return 1;
15 }
16
17 printf("this is linux!\n");
18 fflush(stdout);
19
20 close(fd);
21 return 0;
22 }
我們關掉1,本來時列印在顯示幕上的卻在檔案中,這就是重定向,

重定向的本質

關閉1時,1就不再指向標準輸出了而是指向了新的檔案,此時往顯示幕上輸出就會在新的檔案中,
dup2函式

我們直接把3的內容拷貝到2中,也就完成了重定向,Linux提供的系統呼叫就是dup2這個函式,
dup2函式:
int dup2(int oldfd, int newfd);
1 #include<stdio.h>
2 #include <sys/types.h>
3 #include <sys/stat.h>
4 #include <fcntl.h>
5 #include<unistd.h>
6
7 int main()
8 {
9 int fd = open("y.txt",O_WRONLY|O_CREAT,00644);
10 if(fd < 0)
11 {
12 perror("open");
13 return 1;
14 }
15 close(1);
16 dup2(fd,1);
17
18 printf("this is linux!\n");
19 fprintf(stdout,"hello fprintf\n");
20
21 close(fd);
22 return 0;
23 }

資料被輸入到了y.txt中了,完成了重定向
FILE
因為IO相關函式與系統呼叫介面對應,并且庫函式封裝系統呼叫,所以本質上,訪問檔案都是通過fd訪問的,所以C庫當中的FILE結構體內部,必定封裝了fd
1 #include<stdio.h>
2 #include <sys/types.h>
3 #include <sys/stat.h>
4 #include <fcntl.h>
5 #include<unistd.h>
6 #include<string.h>
7 int main()
8 {
9 const char *msg0="hello printf\n";
10 const char *msg1="hello fwrite\n";
11 const char *msg2="hello write\n";
12 printf("%s", msg0);
13 fwrite(msg1, strlen(msg0), 1, stdout);
14 write(1, msg2, strlen(msg2));
15 fork();
16 return 0;
17 }
程式運行的結果:

對程式進行重定向

我們發現只有系統呼叫的write列印了1遍,printf,fwrite都輸出了2遍,一般C庫函式寫入檔案是全緩沖,寫入顯示幕是行緩沖
重定向影響了緩沖的方式,重定向到普通檔案時,資料的緩沖方式由全緩沖變成了行緩沖,我們放入到緩沖區的資料不會被立即重繪,甚至fork之后,
到行程退出后會統一重繪,寫入檔案中,但是fork的時候,父子資料會發生寫時拷貝,所以當你父行程準備重繪的時候,子行程也就有了同樣的一份資料,就產生兩份資料,write沒有變化就說明沒有緩沖,
注意:
這里說的緩沖區都是用戶級緩沖區,這個緩沖區是有C語言庫函式提供的
感興趣的可以研究FILE的結構體,
本篇文章暫時到這里就結束了,由于博主水平有限,如有錯誤,還請指出,萬分感謝!!!

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/388189.html
標籤:其他
上一篇:.catchError()不會在flutter中拋出例外
下一篇:事件切換鍵組合
