天天看點

open、creat、write、close、lseek等檔案操作函數詳解

首先我們回憶一下,stdin&stdout&stderr

C預設會打開三個輸出輸入流,分别是stdin,stdout,stderr。且這三個流的類型都是FILE*,fopen傳回值類型,檔案指針

檔案操作

檔案操作的一般過程:

打開檔案,打開成功後,應用程式将獲得檔案描述符;

應用程式使用檔案描述符對檔案進行讀寫等操作;

全部操作完畢後,應用程式需要将檔案關閉以釋放用于管理打開檔案的記憶體;

一、open和openat函數:系統調用可以打開或建立一個檔案

1、看一下open函數:

open、creat、write、close、lseek等檔案操作函數詳解

(圖中create函數在下面講解)

參數說明:

pathname:指向欲打開的檔案路徑字元串

flags :打開檔案時,可以傳入多個參數選項,用下面的一個或者多個常量(隻列出了一部分)進行“或”運算,構成flags.(如下)

open、creat、write、close、lseek等檔案操作函數詳解

注:open函數具體使用那個,和具體場景有關。比如,目标檔案不存在,需要open建立,則第三個參數表示檔案的預設權限(預設權限請看文章第三點對umask的介紹​​點選打開連結​​)。

否則就使用兩個參數即可。

傳回值:

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

失敗:-1

2、看一下openat函數

open、creat、write、close、lseek等檔案操作函數詳解

可以看出來,參數dirfd将open函數和openat函數區分開來,共有三種可能性:

(1)path參數指定的是絕對路徑名,在這種情況下,fd參數被忽略,openat函數相當于open函數

(2)path參數指定的是相對路徑名,fd參數指出了相對路徑名在檔案系統中的開始位址。

fd參數是通過打開相對路徑名所在的目錄來擷取。

(3)path參數指定了相對路徑名,fd參數具有特殊值AF_FDCWD。在這種情況下,路徑名在目前工作目錄中擷取,openat函數在操作上與open函數類似。

是以,openat函數是希望解決兩個問題:

(1)讓線程可以使用相對路徑名打開目錄中的檔案

(2)可以避免time-of-check-of-use(TOCTTOU)錯誤。

二、函數creat-建立一個新檔案

見上圖open。

此函數等效于:

open(path,O_WRONLY|O_CREAT|O_TRUNC,mode);

因為creat函數是以隻寫方式打開所建立的檔案。

三 、read函數:系統調用從打開的檔案中讀取資料

如下:

open、creat、write、close、lseek等檔案操作函數詳解

參數:

fd:要讀取的檔案的描述符。

buf:讀取到的資料要放入的緩沖區。

count:要讀取的位元組數。

傳回值:

若成功傳回讀到的位元組數,若已到檔案結尾則傳回0

若出錯則傳回-1并設定變量errno的值。

(注意:1. 這裡的size_t是無符号整型,ssize_t是有符号整型。2. buf指向的記憶體空間必須事先配置設定好)

會由多種情況使實際讀到的位元組數少于要求讀的位元組數:

(1)讀普通檔案時,在要求讀到的位元組數之前已達到了檔案尾端。

(2)當從終端裝置讀時,通常一次隻能讀一行

(3)當從網絡讀時,網絡中的緩沖機制可能造成傳回值小于所要求讀的位元組數。

(4)當從管道或FIFO讀時,如若管道包含的位元組少于所需的數量,那麼read隻能傳回實際可用的位元組數。

(5)當從某些面向記錄的裝置(如錄音帶),一次最多傳回一個記錄。

四、write:系統調用向打開的檔案寫資料

如下:

open、creat、write、close、lseek等檔案操作函數詳解

參數:

fd:要寫入的檔案的描述符。

buf:要寫入的資料所存放的緩沖區。

count:要寫入的位元組數。

傳回值:

若成功傳回已寫的位元組數

出錯則傳回-1并設定變量errno的值

write出錯的一個常見原因是磁盤已寫滿,或者超出了一個給定程序的檔案長度限制。

對于普通檔案,寫操作從檔案的目前偏移量處開始。如果在打開該檔案時,指點了O_APPEND選項,則在每次寫操作之前,将檔案偏移量設定在檔案的目前結尾處,在一次成功寫之後,該檔案偏移量增加實際寫的位元組數。

五、close:系統調用關閉一個打開的檔案。

open、creat、write、close、lseek等檔案操作函數詳解

參數:

fd:要關閉的檔案的描述符。

傳回值:若成功傳回0

出錯則傳回-1

注:當一個程序終止時,核心會自動關閉它所有打開的檔案

六 、lseek:系統調用可以改變檔案偏移量(File Offset)。

檔案偏移量是一個整數,表示距檔案起始處的位元組數

open、creat、write、close、lseek等檔案操作函數詳解

whence必須是以下三個常量之一:

SEEK_SET:将檔案偏移量設定在距檔案開始處offset個位元組。

SEEK_CUR:将檔案偏移量設定在其目前值加offset,offset可正可負。

SEEK_END:将檔案偏移量設定為檔案長度加offset,offset可正可負。

若成功,則傳回新的檔案偏移量。若出錯,傳回-1。

注意:通常,檔案的目前偏移量應當是一個非負整數,但是,某些裝置也可能允許負的偏移量。但對于普通檔案,其偏移量必須是非負值。

是以在比較lseek的傳回值時不要測試其是否小于0,而要測試它是否等于-1。

lseek僅将目前的檔案偏移量記錄在核心中,它并不引起任何I/O操作。然後,該偏移量用于下一個讀或寫操作。

空洞,這一點是允許的。位于檔案中但沒有寫過的位元組都被讀為0。

檔案中的空洞并不要求在磁盤上占用存儲區。

eg:

1、hellow.c 寫檔案

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 
  8 int main(){
  9     umask(0);
 10     int fd=open("myfife",O_WRONLY|O_CREAT,0644);
 11     if(fd<0){
 12         perror("open");
 13         return 1;
 14     }
 15 
 16     int count=5;
 17     const char *msg="hello bit!\n";
 18     int len=strlen(msg);
 19 
 20     while(count--){
 21         write(fd,msg,len);
 22     }      
24     close(fd);
 25     return 0;
 26 }      

結果,建立了檔案myfife且寫入成功

open、creat、write、close、lseek等檔案操作函數詳解

2、hellor.c讀檔案

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 
  8 int main(){
  9     int fd=open("myfife",O_RDONLY);
 10     if(fd<0){
 11         perror("open");
 12         return 1;
 13     }
 14 
 15     const char *msg="hello bit!\n";
 16     char buf[1024];
 17 
 18     while(1){
 19         ssize_t s=read(fd,buf,strlen(msg));
 20         if(s>0){
 21             printf("%s",buf);
 22         }else{
 23             break;      
24         }
 25     }
 26 
 27     close(fd);
 28     return 0;
 29 }      

結果:将剛寫入的檔案讀出:

繼續閱讀