1.1 文件描述符
文件描述符(fd)相當於windows編程中的文件句柄,使一個非負整數,引用一個打開的文件。
Unix的慣例是文件描述符0(STDIN_FILENO)是標準輸出,1(STDOUT_FILENO)是標準輸出,2(STDERR_FILENO)是標準錯誤輸出。
1.2 文件的打開與關閉
1.2.1 相關函數
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
int creat(const char *pathname, mode_t mode);
int close(int fd);
1.2.2 flag的選項
O_RDONLY、O_WRONLY和O_RDWR,這三個標誌中只能指定一個。另外還有以下常數可以選擇:O_APPEND、O_CREAT、O_EXEL(與O_CREAT同時指定,而文件已存在則出錯,否則創建)、O_TRUNC、O_NONBLOCK(非阻塞方式)、O_SYNC(同步寫,每次write都等到物理I/O完成)等常用選項。
1.2.3 創建新文件
當flags指定O_CREAT時,需要指定第三個參數mode,說明新文件的存取權限。也可以用creat函數,creat等價於:
open(pathname, O_WRONLY | O_CREAT | O_TRUNC, mode)
1.3 改變文件的偏移量
1.3.1 相關函數
off_t lseek(int fildes, off_t offset, int whence);
1.3.2 設置文件位移量
參數offset指定偏移量,參數whence可指定爲SEEK_SET(相對於文件頭)、SEEK_CUR(相對於當前位置)、SEEK_END(相對於從文件尾)。
因爲位移量可能是負值,比較lseek的返回值時必須謹慎,不要測試它是否小於0,而要測試它是否等於-1。
1.3.3 文件空洞
文件的位移量可以大於文件當前長度,這種情況下,對該文件的下一次寫操作將延長該文件。形成一個空洞,空洞中的字節都爲0。
1.4 文件的讀寫
1.4.1 相關函數
ssize_t read(int fd, void *buf, size_t count);
ssize_t write(int fd, const void *buf, size_t count);
1.4.2 讀文件
read函數的返回值是實際讀到的字節數,他可能少於要求讀的字節數count:讀到文件尾了;或者讀的是終端設備、網絡設備或者某些面向記錄的設備時。
1.4.3 寫文件
寫操作從當前位移開始。若打開文件時設置了O_APPEND選項,則每次寫之前,都會將當前位移量設爲文件尾。
1.4.4 效率
使用不同的BUFFSIZE將數據從標準輸入讀入然後寫到標準輸出。在下面的測試中,標準輸入重定向到一個7175K的文件,標準輸出重定向到/dev/null。
BUFFSIZE爲1:
real 0m15.945s
user 0m5.420s
sys 0m10.500s
BUFFSIZE爲4:
real 0m4.025s
user 0m1.570s
sys 0m2.460s
BUFFSIZE爲16:
real 0m1.057s
user 0m0.200s
sys 0m0.860s
BUFFSIZE爲256:
real 0m0.153s
user 0m0.030s
sys 0m0.120s
BUFFSIZE爲1024:
real 0m0.093s
user 0m0.000s
sys 0m0.100s
BUFFSIZE爲4096:
real 0m0.081s
user 0m0.010s
sys 0m0.080s
BUFFSIZE爲16384:
real 0m0.078s
user 0m0.000s
sys 0m0.080s
BUFFSIZE爲65536:
real 0m0.080s
user 0m0.000s
sys 0m0.080s
繼續增大BUFFSIZE對系統時間並沒有影響。
1.5 複製文件描述符
1.5.1 相關函數
int dup(int oldfd);
int dup2(int oldfd, int newfd);
1.5.2 說明
這些函數返回一個和oldfd共享同一文件表項的新fd。不同之處是dup2可以指定新fd的值,並且如果newfd已經打開,則先將其關閉。他們可以用fcntl(oldfd,F_DUPFD, 0/newfd)實現,不同的只是errno,並且dup2是一個原子操作。
1.6 fcntl函數
1.6.1 相關函數
int fcntl(int fd, int cmd);
int fcntl(int fd, int cmd, long arg);
int fcntl(int fd, int cmd, struct flock *lock);
1.6.2 功能
- 複製一個現存的描述符(cmd=F_DUPFD)。
- 獲得/設置文件描述符標誌(cmd = F_GETFD或F_SETFD)。
- 獲得/設置文件狀態標誌(cmd d = F_GETFL或F_SETFL)。
- 獲得/設置異步I / O有權(cmd = F_GETOWN或F_SETOWN)。
- 獲得/設置記錄鎖(cmd = F_GETLK, F_SETLK或F_SETLKW)。
1.6.3 F_GETFL或F_SETFL
對於這兩種操作,可以獲得或者設置文件的狀態標誌。F_GETFL時可以獲得O_RDONLY、O_WRONLY、O_RDWR、O_APPEND、O_NONBLOCK、O_SYNC和O_ASYNC。對於前三種標誌,必須使用屏蔽字O_ACCMODE,然後將結果與這三種標誌一一比較。F_SETFL時只能設置後四種標誌。
accmode = val & O_ACCMODE;
if (accmode == O_RDONLY) …
else if (accmode == O_WRONLY) …
else if (accmode == O_RDWR) …
else err_dump("unknown access mode");
if (val & O_APPEND) …
if (val & O_NONBLOCK) …
……
1.7 記錄鎖
1.7.1 相關函數:
int fcntl(int fd, int cmd);
int fcntl(int fd, int cmd, struct flock *lock);
1.7.2 相關結構:
struct flock {
short l_type; /* F_RDLCK, F_WRLCK, F_UNLCK */
short l_whence; /* SEEK_SET, SEEK_CUR, SEEK_END */
off_t l_start; /* Starting offset for lock */
off_t l_len; /* Number of bytes to lock */
pid_t l_pid; /* PID of process blocking our lock */
};
l_start和l_whence決定加鎖或解鎖區域的起始位置,l_len決定其長度。該區域可以越過文件尾端,但不能越過文件起始位置。l_len爲0,則表示鎖的區域從開始位置直至文件尾,而不管文件如何增長。鎖整個文件的通常方法是:l_start爲0,l_whence爲SEEK_SET,l_len爲0。
1.7.3 共享鎖和獨佔鎖
共享鎖,又叫讀鎖(RDLCK);獨佔鎖,又叫寫鎖(WRLCK)。
表格 1 (讀鎖和寫鎖)
當前所有/要求 |
讀鎖 |
寫鎖 |
讀鎖(一把或多把) |
可以 |
拒絕 |
寫鎖 |
拒絕 |
拒絕 |
1.7.4 加鎖和解鎖
根據fcntl函數的cmd參數進行不同操作:
-
F_GETLK:檢查是否可以建立參數lock描述的鎖
- F_SETLK:設置lock描述的鎖,出錯立刻返回
- F_SETLKW:F_SETLK的阻塞版,若不能加鎖則等待