首先我們回憶一下,stdin&stdout&stderr
C預設會打開三個輸出輸入流,分别是stdin,stdout,stderr。且這三個流的類型都是FILE*,fopen傳回值類型,檔案指針
檔案操作
檔案操作的一般過程:
打開檔案,打開成功後,應用程式将獲得檔案描述符;
應用程式使用檔案描述符對檔案進行讀寫等操作;
全部操作完畢後,應用程式需要将檔案關閉以釋放用于管理打開檔案的記憶體;
一、open和openat函數:系統調用可以打開或建立一個檔案
1、看一下open函數:

(圖中create函數在下面講解)
參數說明:
pathname:指向欲打開的檔案路徑字元串
flags :打開檔案時,可以傳入多個參數選項,用下面的一個或者多個常量(隻列出了一部分)進行“或”運算,構成flags.(如下)
注:open函數具體使用那個,和具體場景有關。比如,目标檔案不存在,需要open建立,則第三個參數表示檔案的預設權限(預設權限請看文章第三點對umask的介紹點選打開連結)。
否則就使用兩個參數即可。
傳回值:
成功:新打開的檔案描述符
失敗:-1
2、看一下openat函數
可以看出來,參數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函數:系統調用從打開的檔案中讀取資料
如下:
參數:
fd:要讀取的檔案的描述符。
buf:讀取到的資料要放入的緩沖區。
count:要讀取的位元組數。
傳回值:
若成功傳回讀到的位元組數,若已到檔案結尾則傳回0
若出錯則傳回-1并設定變量errno的值。
(注意:1. 這裡的size_t是無符号整型,ssize_t是有符号整型。2. buf指向的記憶體空間必須事先配置設定好)
會由多種情況使實際讀到的位元組數少于要求讀的位元組數:
(1)讀普通檔案時,在要求讀到的位元組數之前已達到了檔案尾端。
(2)當從終端裝置讀時,通常一次隻能讀一行
(3)當從網絡讀時,網絡中的緩沖機制可能造成傳回值小于所要求讀的位元組數。
(4)當從管道或FIFO讀時,如若管道包含的位元組少于所需的數量,那麼read隻能傳回實際可用的位元組數。
(5)當從某些面向記錄的裝置(如錄音帶),一次最多傳回一個記錄。
四、write:系統調用向打開的檔案寫資料
如下:
參數:
fd:要寫入的檔案的描述符。
buf:要寫入的資料所存放的緩沖區。
count:要寫入的位元組數。
傳回值:
若成功傳回已寫的位元組數
出錯則傳回-1并設定變量errno的值
write出錯的一個常見原因是磁盤已寫滿,或者超出了一個給定程序的檔案長度限制。
對于普通檔案,寫操作從檔案的目前偏移量處開始。如果在打開該檔案時,指點了O_APPEND選項,則在每次寫操作之前,将檔案偏移量設定在檔案的目前結尾處,在一次成功寫之後,該檔案偏移量增加實際寫的位元組數。
五、close:系統調用關閉一個打開的檔案。
參數:
fd:要關閉的檔案的描述符。
傳回值:若成功傳回0
出錯則傳回-1
注:當一個程序終止時,核心會自動關閉它所有打開的檔案
六 、lseek:系統調用可以改變檔案偏移量(File Offset)。
檔案偏移量是一個整數,表示距檔案起始處的位元組數
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且寫入成功
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 }
結果:将剛寫入的檔案讀出: