這次回顧APUE中第三四章的內容,主要是文件I/O操作相關的接口函數。
UNIX系統的文件I/O是不帶緩沖的I/O,不帶緩沖是指每個read和write都調用系統內核的一個系統調用。
1.文件描述符
UNIX I/O的所有函數都是基于文件描述符來操作的。那什么是文件描述符呢?文件描述符是一個非負整數。當打開一個現有文件或創建一個新文件時,內核向進程返回一個文件描述符。該文件描述符fd是所有UNIX I/O函數的操作對象。UNIX系統把文件描述符0與進程標準輸入關聯,把文件描述符1與進程標準輸出關聯,把文件描述符2與標準錯誤關聯。我們一般在程序中用STDINPUT_FILENO,STDOUTPUT_FILENO,STDERR_FILENO代替這幾個文件描述符。文件描述符的范圍是0~OPEN_MAX-1。
2.基本I/O函數
#include <fcntl.h>
int open(const char *path,int oflag,.../* mode_t mode */); /* xx */
int openat(int fd,const char *path,int oflag,.../* mode_t mode */);
【成功返回文件描述符,出錯返回-1】
調用open函數打開一個文件,path是要打開或創建的文件的名字,oflag用來說明該函數的多個選項。對于openat函數,在UNIX這一系列I/O函數中有很多類似openat帶at后綴的xxat函數,它們的功能與xx函數類似,只不過是xx函數是用文件的絕對路徑名來調用,而xxat函數是用文件描述符加上相對路徑名來調用,對xxat類函數來說,當path參數指向一個絕對路徑名時,其參數fd也失效,此時xxat函數與xx函數相同。(再后面對于這種函數我會用xx注釋說明,就不再列出xxat函數了)。
open函數的oflag參數是用多個系統定義的常量做‘或’運算得出。首先是O_RDONLY,O_WRONLY,O_RDWR,O_EXEC,O_SEARCH(這五個常量中必須指定一個且只能指定一個)。剩下的我只列出幾個我覺得用的頻繁些的:O_APPEND,每次寫時都追加到文件末尾;O_CREAT,若此文件不存在則創建,使用該選項時,函數第三個參數mode需指定文件訪問權限;O_TRUNC,若文件存在,且是只寫或讀-寫打開,則將文件長度截斷為零。
#include <fcntl.h>
int creat(const char *path,mode_t mode);
【成功,返回以WRONLY打開的文件描述符;出錯返回-1】
#include <unistd.h>
int close(int fd);【成功,返回0;出錯返回-1】
注:當一個進程終止時,內核會自動關閉它打開的所有文件,因此很多程序都利用這一點不顯式調用close關閉。
off_t lseek(int fd,off_t offset,int whence);【成功,返回文件新的偏移量;失敗返回-1】
whence有三種值:SEEK_SET,此時文件偏移量設置為據文件開始初offset個字節處;SEEK_CUR,此時將文件偏移量設置為其當前值加offset;SEEK_END,此時文件偏移量設置為文件長度加offset。
ssize_t read(int fd,void *buf,size_t nbytes);【成功,返回讀到字節數,若已到文件尾,返回零;出錯返回-1】
從文件描述符所指文件讀n字節到buf數組。ssize_t是帶符號返回值int,size_t是unsigned int
ssize_t write(int fd,void *buf,size_t nbytes);【成功,返回已寫字節數;出錯返回-1】
從buf數組讀n字節寫入fd所指文件。對普通文件,寫操作從文件當前偏移量出開始;對于文件打開時指定了O_APPEND位,每次寫操作是在文件末尾。
3.文件共享
UNIX支持在不同進程間共享打開文件。UNIX內核表示打開文件的數據結構如下所示(手機拍的湊合著看):
a.每個進程在進程表中都有一個記錄項,記錄項包含一張打開文件的文件描述符表,表中每一項關聯文件描述符標志及一個指向文件表項的指針。
b.內核為所有打開文件維持一張文件表,每個表項包含文件狀態標志,當前文件偏移量,v節點指針。
c.每個打開文件都有一個v節點結構。v節點包含了文件類型和對文件進行各種操作的函數指針。還包含了文件的i節點,i節點包含了文件的所有者,文件長度,指向文件實際數據塊在磁盤上的指針等信息。
兩獨立進程各自打開同一文件的示意圖:
#include <unistd.h>
int dup(int fd);【成功,返回新文件描述符,出錯返回-1】
復制現有文件描述符,返回的文件描述符是當前可用的文件描述符中最小的那個。
int fsync(int fd);
int fdatasync(int fd);
【成功,返回0,出錯返回-1】
void sync(void);
sync只是將所修改的塊緩沖區加入寫隊列,然后就返回,不等待寫磁盤操作解數。
fsync只對文件描述符fd指定的文件有用,且要等寫磁盤操作完成才返回。
fdatasync類似于fsync,只是fdatasync只影響文件數據部分。
#include <fcntl.h>
int fcntl(int fd,int cmd,.../* arg */);
該函數用于改變已打開文件的屬性。fcntl的功能與cmd有關。
To be continued...
新聞熱點
疑難解答