1. 程式人生 > >【Linux】檔案相關係統呼叫介面(IO)

【Linux】檔案相關係統呼叫介面(IO)

早期在寫C語言介面的時候,我們可以通過fopen來開啟一個檔案,下面這段兩段程式碼為例:

hello.c寫檔案

  1 #include <stdio.h>                                                          
  2 #include <string.h>
  3  int main ()
  4 {
  5     FILE* fp=fopen("myfile","w");
  6     if(!fp){
  7         printf("fopen error!\n");
  8     }
  9     const char *msg="hello world!\n";
 10     int count = 5;
 11     while(count--){
 12         fwrite(msg,strlen(msg),1,fp);
 13     }
 14     fclose(fp);
 15     return 0;
 16 }

hello.c讀檔案

  1 #include <stdio.h> 
  2 #include <string.h>
  3  int main ()
  4 {
  5     FILE* fp=fopen("myfile","r");
  6     if(!fp){
  7         printf("fopen error!\n");
  8     }
  9     char buf[1024];
 10     const char *msg="hello world!\n";
 11     while(1){
 12         ssize_t s=fread(buf,1,strlen(msg),fp);
 13         if(s>0){
 14             buf[s]=0;
 15             printf("%s",buf);
 16         }
 17         if(feof(fp)){
 18             break;
 19         }
 20     }
 21     fclose(fp);
 22     return 0;
 23 }  

顯而易見,是要往“myfile”檔案中寫五條“helloworld”,再通過讀檔案介面讀出來。這裡我們運用了fwrite、fread這些C語言介面。

 

如果我們想把一個字串顯示在顯示器上,我們可以用 printf、putchar、fputchar、fputs、fprintf、fwrite.......等等一系列介面。而我們也知道任何一個程序在啟動之後,預設開啟三個輸入輸出流,分別為stdin、stdout、stderr,分別對應的裝置是鍵盤、顯示器、顯示器。仔細觀察發現,這三個流的型別都是FILE*,我們用fopen開啟檔案該返回值的型別就是FILE*。而這個FILE*

是C語言提供的資料型別,所以說,這三個流與C語言強相關,都是C語言提供的介面。

 

這是我們的作業系統結構,通過這張圖以及之前的知識我們知道,作業系統不會直接將自己的每個管理模組暴露出來給使用者,而是通過一系列的系統呼叫介面。而剛剛提到的C語言提供的那些介面都是處於使用者操作介面的lib中

但是剛才的程式碼表明我們最終將訊息列印到了顯示器上,即硬體。可是C庫操作介面在上層的使用者操作介面處,而硬體是在下面的硬體部分,所以說明我們必定要將要寫入的資料自頂向下的交付給底層的硬體,但是要交付肯定不是C庫直接去交付,因為我們沒有這個權利,這就必定要通過作業系統來完成,也就是要通過系統呼叫介面。也就是說,我們的C庫中,必定封裝了對應的系統呼叫介面。

 

所以,我們現在可以以open為例看看系統呼叫介面,並且用系統呼叫介面來實現剛才的程式碼。

open

#include <sys/sypes.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);

pathname: 要開啟或建立的目標檔案

flags: 開啟檔案時,可以傳入多個引數選項,用下面的一個或者多個常量進行“或”運算,構成flags。
引數:

O_RDONLY: 只讀開啟

O_WRONLY: 只寫開啟

O_RDWR : 讀,寫開啟

這三個常量,必須指定一個且只能指定一個

O_CREAT : 若檔案不存在,則建立它。需要使用mode選項,來指明新檔案的訪問許可權

O_APPEND: 追加寫

返回值:

成功:新開啟的檔案描述符

失敗:-1

類比C庫呼叫介面,我們明白fopen底層必定呼叫了open。 下面用檔案的系統呼叫介面來實現剛剛的程式碼

hello.c寫檔案

  1 #include <stdio.h>                                                          
  2 #include <string.h>
  3 #include <sys/stat.h>
  4 #include <sys/types.h>
  5 #include <unistd.h>
  6 #include <fcntl.h>
  7  
  8  int main ()
  9 {
 10     umask(0);//設定允許當前程序建立檔案或者目錄最大可操作的許可權
 11     int fd = open("myfile",O_WRONLY|O_CREAT,0644);
 12     if(fd<0) {
 13         perror("open");
 14         return 1;
 15     }
 16     int count = 5;
 17     const char *msg = "hello world!\n";
 18     int len = strlen(msg);
 19     while (count--){
 20         write(fd,msg,len);//fd:檔案描述符    msg:緩衝區首地址   len:本次讀取期
                              望寫入多少位元組的資料       返回值:實際寫了多少位元組的資料
 21     }
 22     close(fd);
 23     return 0;
 24 }  

hello.c讀檔案 

  1 #include <stdio.h>
  2 #include <string.h>
  3 #include <sys/stat.h>
  4 #include <sys/types.h>
  5 #include <unistd.h>
  6 #include <fcntl.h>
  7  
  8  int main ()      
  9 {
 10     int fd = open("myfile",O_RDONLY);       
 11     if(fd<0) {    
 12         perror("open");      
 13         return 1; 
 14     }   
 15     const char *msg = "hello world!\n";    
 16     char buf[1024];          
 17     while(1){     
 18         ssize_t s=read(fd,buf,strlen(msg));//類比write
 19         if(s>0){  
 20             printf("%s",buf);
 21         }else{   
 22             break;
 23         }
 24     }
 25     close(fd);
 26     return 0;
 27 }

 

 

open、close、read、write、lseek 都屬於系統提供的介面,稱之為系統呼叫介面。所以,可以認為,f#系列的函式,都是對系統呼叫的封裝,方便二次開發。