3.1 引言<?xml:namespace prefix = o />
大多數unix系統只需要5個函數:open,read,write,lseek,close
這些函數被稱爲不帶緩衝的I/O,是指每個read和write函數都調用內核中的一個系統調用。他們不是ISO C的組成部分,但是POSIX.1和Single Unix Specification的組成部分。
多個進程間共享資源,需要原子操作
3.2 文件描述符
對內核而言,所有打開的文件都是通過文件描述符引用。打開或創建文件時,內核向進程返回一個文件描述符,度或寫文件時,將文件描述符作爲參數傳遞給read和write。
慣例:標準輸入、輸出、出錯分別用0、1、2,打開shell時自動打開;分別用符號STDIN_FILENO/STDOUT_FILENO/STDERRO_FILENO
3.3 open函數
#include <fcnl.h>
int open(const char *pathname,int oflag,.../*mode_t mode*/)
成功則返回文件描述符,出錯返回-1
oflag參數(下面只能選其一):
O_RDONLY 只讀打開
O_WRONLY 只寫打開
O_RDWR 讀寫打開
下列爲可選:
O_APPEND
O_CREAT
O_EXCL
O_TRUNC
O_NOCTTY
O_NONBLOCK
文件名和路徑截斷
3.4 creat函數
#include <fcnl.h>
int creat(const char *pathname,mode_t mode);
成功則返回一個爲只寫打開的文件描述符,出錯則返回-1
等效於:
open(pathname,O_WRONLY | O_CREAT | O_TRUNC, mode);
不足:只能以只寫打開
3.5 close函數
#include <fcnl.h>
int close(int fileds);
進程終止時,內核自動關閉它所打開的文件
3.6 lseek函數
系統默認:除非使用O_APPEND選項,否則打開文件時該偏移量被設置爲0
#include <unistd.h>
off_t lseek(int fileds, off_t offset, int whence);
whence:SEEK_SET,SEEK_CUR,SEEK_END
管道、FIFO或網絡套接字,不支持,返回-1
普通文件的偏移量必須是非負值;其他設備的偏移量可能是負值;所以在比較lseek的返回值時,不要測試它是否小於0,而要測試它是否等於-1。(若偏移量恰好等於-1呢?)
Lseek可能造成文件空洞;文件的空洞並不要求在磁盤山佔用存儲區,處理方法與實現有關。
Od命令可以觀察文件的實際內容
3.7 read函數
#include <unistd.h>
Ssize_t read(int fields,void *buf,size_t nbytes);
若成功則返回讀到的字節數,若已到達文件結尾則返回0,若出錯則返回-1。
sszie_t 帶符號整數
size_t 不帶符號整數
3.8 write函數
#include <unistd.h>
Ssize_t write(int fieldes,const void *buf,size_t nbytes);
若成功返回已寫字節數,出錯則返回-1
3.9 I/O的效率
Buffersize的設置問題
大多數文件系統爲改善其性能都採用某種預讀技術。當檢測到正進行順序讀取時,系統就試圖讀入比應用程序所要求更多的數據,並假想應用程序很快就會讀這些數據。
3.10 文件共享
Unix系統支持在不同進程間共享打開的文件。
一個進程打開兩個文件
兩個獨立進程打開同一個文件
每個進程都有自己的文件表項:每個進程都有自己對該文件的當前偏移量,及讀寫方式
3.11 原子操作
添加至一個文件:
If (lseek(fd,0L,2) < 0)
Err_sys("lseek error");
If (write(fd,buf,100) != 100)
Err_sys("write error");
多進程的情況下,由於內核的切換,上述操作存在問題。
解決:使之成爲原子操作,在打開文件時設置O_APPEND標誌
#include <unistd.h>
Ssize_t pread(int filedes,void *buf,size_t nbytes,off_t offset);
Ssize_t pwrite(int filedes,const void *buf,size_t nbytes,off_t offset);
原子性地定位搜索和執行I/O
3.12 dup和dup2函數
#include <unistd.h>
Int dup(int filedes);
Int dup2(int filedes,int fiedes2);
若成功則返回新的文件描述符,若出錯則返回-1
dup返回的新描述符一定是當前可用文件描述符中的最小數值;
dup2則可用field2參數指定新描述的數值。
3.13 sync、fsync和fdatasync函數
延遲寫
這三個函數保證磁盤上實際文件系統與緩衝區高速緩存中內容的一致性。
//將所有修改過的塊緩衝區排入寫隊列,然後返回;不等實際磁盤操作結束
void sync(void);
//只對fields指定的單一文件起作用,並等待磁盤操作結束。修改數據部分和文件的屬性。
int fsync(int fields);
//同上,但只更新數據部分
int fdatasync(int fields);
3.14 fcntl函數
#include <fcntl.h>
Int fcntl(int fieldes,int cmd,.../*int arg*/);
若成功則依賴於cmd,若出錯則返回-1
Fcntl函數的5種功能:
(1)複製現有的描述符(cmd = F_DUPED)
(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)
3.15 ioctl函數
I/O操作的雜物箱。
3.16 /dev/fd