1.檔案描述符
檔案描述符是一個非負整數,當開啟一個現有檔案或建立一個新檔案時候,核心向進程返回一個檔案描述符。Unix系統shell使用檔案描述符0與進程的標準輸入相關聯,檔案描述符1與進程的標準輸出相關聯,檔案描述符2與進程的標準出錯相關聯,在POSIX標準中,幻數0、1、2應當替換為符號常量STDIN_FILENO、STDOUT_FILENO和STDERR_FILENO,另外檔案描述符變化範圍:0~OPEN_MAX,現在很多系統將OPEN_MAX置為63
2.open函數
調要open函數可以開啟或建立一個檔案。
函數原型
#include <fcnt1.h>int open(const char *pathname,int oflag,/*mode_t made*/);
pathname是需要開啟的檔案;
oflag參數用來說明此函數的多個選項。用 O_RDONLY(唯讀),O_WRONLY(唯寫),O_REWR(讀寫)。這三個常量必須指定,有且只能指定一個,並且和下列多個常量進行或運算構成:
O_APPEND 每次寫時都追加到檔案的尾端
O_CREAT 若檔案不存在則建立它,需要第三個參數為指定檔案的存取權限
O_EXCL 若同時指定O_CREAT,而檔案存在則會出錯,用此則可以測試檔案是否存在,若不存在則建立這個檔案
O_TRUNC 如果此檔案不存在,而且為唯寫或讀寫成功開啟,則將其長度截短為0
O_NOCTTY 若pathname指的是終端裝置,則不將該裝置分配為此進程的控制端
O_NONBLOCK 非阻塞模式
這些常量是可選擇的
3.create函數
函數原型
#include <fcnt1.h>int create(const char *pathname,mode_t mode);
此函數等效於
open(pathname,O_WRONLY | O_CREAT | O_TRUNC,mode);
4.close函數
函數原型
#include<fcnt1.h>int close (int filedes); //傳回值若成功返回0不成功返回-1
5.lseek函數
可以用lseek顯式地為一個開啟的檔案設定其位移量。
函數原型
#include<unistd.h>off_t lseek(int fileds,off_t offset,int whence);//若成功則返回新的檔案位移量,若出錯則返回-1
參數whence可以置為下值
SEEK_SET,則將該檔案的位移量設定為距檔案開始出offset個位元組
SEEK_CUR,則將該檔案的位移量設定為其當前值加offset,offset可正可負
SEEK_END,則將該檔案的位移量設定為檔案長度加offset,offset可正可負
若lseek成功執行,則返回新的檔案位移量,為此可以用下列方式確定開啟檔案的當前位移量
off_t currpos;currpos = lseek(fd,0,SEEK_CUR);
這種方法也可以用來確定所涉及的檔案是否可以設定位移量,如果檔案描述符引用的是一個管道、FIFO進而網路通訊端,則lseek返回-1,並將errorn設定為ESPIPE。
注意:
1).lseek僅將當前的檔案位移量記錄在核心中,它並不引起任何I/O操作
2).檔案位移量可以大於檔案的當前長度,在這種情況下,對該檔案下一次的寫將加長該檔案,並在檔案構成一個空洞,這一點是允許的。位於檔案中但沒有寫過的位元組都被設為 0
3).檔案中的空洞並不要求在磁碟上佔用儲存區。
6.read函數
從開啟的檔案中讀資料到buf
#include <unistd.h>ssize_t read(int filedes,void *buf,size_t nbytes);
傳回值:若成功則返回讀到的位元組數,若已到檔案結尾則返回0,若出錯返回-1;
7.write函數
調用write函數向開啟的檔案寫資料
#include <unistd.h>ssize_t write(int filedes,const void *buf,size_t nbytes);
傳回值:若成功則返回位元組數,若出錯返回-1
註:write出錯的一個常見原因是:磁碟已寫滿,或者超過了一個給定進程的檔案長度限制
8.dup和dup2函數
這兩個函數都用來複製一個現存的檔案描述符
#include <unistd.h> int dup(int filedes); int dup2(int filedes,int filedes2); //filedes2參數指定新描述符的數值。如果filedes2已經開啟,則先關閉。
傳回值:若成功返回新的檔案描述符,若出錯則返回-1
調用
dup(filedes);
等效於
fcntl(filedes, F_DUPFD, 0);
而調用
dup2(filedes, filedes2);
等效於
close(filedes2);fcntl(filedes, F_DUPFD, filedes2);
區別
1).dup2是一個原子操作,而close及fcntl則包括兩個函數調用,有可能在close和fcntl之間插入執行訊號捕獲函數
2).dup2和fcntl有某些不同errorno
9.sync,fsync ,fdatasync函數
為瞭解決延遲寫的問題,保證磁碟上實際檔案系統和緩衝區快取中內容的一致性。
#include <unistd.h> int fsync(int filedes); // 只對由檔案描述符filedes指定的單一檔案其作用,並且等待寫磁碟操作結束 int fdatesync(int filedes); //功能和fsync差不多,但它還同步更新檔案的屬性 void sync(void); //將所有修改過的快緩衝區排入寫隊列,然後返回,它並不等待實際寫磁碟操作結束
10.fcntl函數
可以改變已開啟的檔案性質
#include <fcnt1.h> int fcnt1(int filedes,int cmd, /* int arg *);
第三個參數總是一個整數,與上面所示函數原型中的注釋部分相對應。但是在作為記錄鎖用時,第三個參數則是指向一個結構的指標。
fcntl函數有5種功能:
1).複製一個現有的描述符(cmd=F_DUPFD).
2).獲得/設定檔案描述符標記(cmd=F_GETFD或F_SETFD).
3).獲得/設定檔案狀態標記(cmd=F_GETFL或F_SETFL).
4).獲得/設定非同步I/O所有權(cmd=F_GETOWN或F_SETOWN).
5).獲得/設定記錄鎖(cmd=F_GETLK,F_SETLK或F_SETLKW).
11.ioctl函數
ioctl函數是I/O操作的雜物箱,完成其他函數都無法完成的操作
#include <unistd.h> /*System V*/#include <sys/ioctl.h> /*BSD and Linux*/#include <stropts.h> /*XSI STREAMS*/int ioctl(int filedes, int request, . . .);
詳見APUE第十八章
12./dev/fd
比較新的unix/linux系統都提供名為/dev/fd的目錄,其中有檔案0、1、2等檔案,開啟這些檔案,相當於複製這些檔案描述符
例如:
fd=open("/dev/fd/0",mode);
等價於
fd=dup(0);
檔案描述符fd和0將共用一個檔案表記錄項。
13.檔案分享權限設定
檔案分享權限設定是指不同進程間開啟檔案的共用。核心通過三種資料結構來表示開啟的檔案,
1).每個進程有個進程表項,表中是開啟檔案的描述符向量。每個向量包含了檔案描述符標記和一個指向檔案表項的指標;
2).核心為所有開啟的檔案維護一個檔案表,每個檔案表項包括了a,檔案狀態標記,如讀、寫、添加、非阻塞等b,當前的檔案位移量c,指向檔案v-node表項的指標;
3).每個開啟檔案或裝置都有一個v-node結構 ,包含檔案類型和指向操作檔案的函數的指標。
當兩個以上獨立進程開啟同一個檔案實現檔案分享權限設定時,核心維護不同的檔案表項,就是兩個以上進程表項中的檔案表項指標指向不同的檔案表項,而不同的檔案表項中的v-node指標指向同一個v-node而實現檔案分享權限設定。由於每個進程有自己的開啟檔案表項,所以有自己的檔案開啟狀態以及檔案位移量。
需要注意的是Linux沒有將相關資料分為i節點和v節點,而是採用了一個獨立於檔案系統的i節點(通用i-node結構)和一個依賴於檔案系統的i節點