文件IO編程
一、系統(tǒng)調(diào)用及API
1、 系統(tǒng)調(diào)用
所謂系統(tǒng)調(diào)用就是指操作系統(tǒng)提供給用戶程序調(diào)用的一組“特殊”接口,用戶程序可以通過這組“特殊”接口來獲得操作系統(tǒng)內(nèi)核提供的服務(wù),例如,用戶可以通過進(jìn)程控制相關(guān)的系統(tǒng)調(diào)用來創(chuàng)建進(jìn)程、實現(xiàn)進(jìn)程調(diào)度、進(jìn)程管理等
為了更好地保護內(nèi)核空間(就是為什么用戶程序不能直接訪問系統(tǒng)內(nèi)核提供的服務(wù)),將程序的運行分為內(nèi)核空間和用戶空間,它們運行在不同的級別上,在邏輯上是相互隔離的。
2、 用戶編程接口(API)
系統(tǒng)調(diào)用不是直接與程序員進(jìn)行交互的,它僅僅是一個通過軟中斷機制向內(nèi)核提交請求,以獲取內(nèi)核服務(wù)的接口,實際使用中,程序員調(diào)用的通常是API函數(shù),API遵循了在UNIX中最流行的應(yīng)用編程界面標(biāo)準(zhǔn)——POSIX標(biāo)準(zhǔn)。該標(biāo)準(zhǔn)描述了操作系統(tǒng)的系統(tǒng)調(diào)用編程接口(實際上就是API),用于保證應(yīng)用程序可以在源代碼一級上在多種操作系統(tǒng)上移植運行,這些系統(tǒng)調(diào)用接口主要是通過C庫來實現(xiàn)的。
3、 系統(tǒng)命令
系統(tǒng)命令相對API更高了一層,實際上是一個可執(zhí)行程序(如shell系統(tǒng)命令),它的內(nèi)部引用了用戶編程接口(API)來實現(xiàn)相應(yīng)的功能。
二、文件及文件描述符
在linux中對目錄和設(shè)備的操作都等同于文件的操作,linux中文件分為普通文件、目錄文件、鏈接文件、設(shè)備文件四種。
內(nèi)
核通過文件描述符區(qū)分和引用特定的文件,所有設(shè)備和文件的操作都使用文件描述符來進(jìn)行的,它是一個非負(fù)的整數(shù),是一個索引值,并指向內(nèi)核中每個進(jìn)程打開文
件的記錄表,當(dāng)打開一個現(xiàn)存文件或創(chuàng)建一個新文件時,內(nèi)核就向進(jìn)程返回一個文件描述符,當(dāng)需要讀文件時,也需要把文件描述符作為參數(shù)傳遞給相應(yīng)的函數(shù)。
通常,一個進(jìn)程打開時,都會打開3個文件:標(biāo)準(zhǔn)輸入、標(biāo)準(zhǔn)輸出、和標(biāo)準(zhǔn)出錯處理,這3個文件分別對應(yīng)文件描述符為0,1,2
三、不帶緩存的文件IO操作
不帶緩存是指每一個函數(shù)都只是調(diào)用系統(tǒng)中的一個函數(shù),這些函數(shù)雖然不是ANSI C的組成部分,但都是POSIX的組成部分。
主要用到5個函數(shù):open,read,write,close,lseek。
Open函數(shù)定義:
定義函數(shù) int open( const char * pathname, int flags);
int open( const char * pathname,int flags, int mode);
參數(shù)pathname 被打開的文件名(可包含路徑名)。
參數(shù)flags 所能使用的旗標(biāo):
O_RDONLY 以只讀方式打開文件
O_WRONLY 以只寫方式打開文件
O_RDWR 以可讀寫方式打開文件。上述三種旗標(biāo)是互斥的,也就是不可同時使用,但可與下列的旗標(biāo)利用OR(|)運算符組合。
O_CREAT 若欲打開的文件不存在則自動建立該文件。
O_EXCL 如果O_CREAT 也被設(shè)置,此指令會去檢查文件是否存在。文件若不存在則建立該文件,否則將導(dǎo)致打開文件錯誤。此外,若O_CREAT與O_EXCL同時設(shè)置,并且欲打開的文件為符號連接,則會打開文件失敗。
O_NOCTTY 如果欲打開的文件為終端機設(shè)備時,則不會將該終端機當(dāng)成進(jìn)程控制終端機。
O_TRUNC 若文件存在并且以可寫的方式打開時,此旗標(biāo)會令文件長度清為0,而原來存于該文件的資料也會消失。
O_APPEND 當(dāng)讀寫文件時會從文件尾開始移動,也就是所寫入的數(shù)據(jù)會以附加的方式加入到文件后面。
O_NONBLOCK 以不可阻斷的方式打開文件,也就是無論有無數(shù)據(jù)讀取或等待,都會立即返回進(jìn)程之中。
O_NDELAY 同O_NONBLOCK。
O_SYNC 以同步的方式打開文件。
O_NOFOLLOW 如果參數(shù)pathname 所指的文件為一符號連接,則會令打開文件失敗。
O_DIRECTORY 如果參數(shù)pathname 所指的文件并非為一目錄,則會令打開文件失敗。
此為Linux2.2以后特有的旗標(biāo),以避免一些系統(tǒng)安全問題。參數(shù)mode 則有下列數(shù)種組合,只有在建立新文件時才會生效,此外真正建文件時的權(quán)限會受到umask值所影響,因此該文件權(quán)限應(yīng)該為(mode-umaks)。
S_IRWXU00700 權(quán)限,代表該文件所有者具有可讀、可寫及可執(zhí)行的權(quán)限。
S_IRUSR 或S_IREAD,00400權(quán)限,代表該文件所有者具有可讀取的權(quán)限。
S_IWUSR 或S_IWRITE,00200 權(quán)限,代表該文件所有者具有可寫入的權(quán)限。
S_IXUSR 或S_IEXEC,00100 權(quán)限,代表該文件所有者具有可執(zhí)行的權(quán)限。
S_IRWXG 00070權(quán)限,代表該文件用戶組具有可讀、可寫及可執(zhí)行的權(quán)限。
S_IRGRP 00040 權(quán)限,代表該文件用戶組具有可讀的權(quán)限。
S_IWGRP 00020權(quán)限,代表該文件用戶組具有可寫入的權(quán)限。
S_IXGRP 00010 權(quán)限,代表該文件用戶組具有可執(zhí)行的權(quán)限。
S_IRWXO 00007權(quán)限,代表其他用戶具有可讀、可寫及可執(zhí)行的權(quán)限。
S_IROTH 00004 權(quán)限,代表其他用戶具有可讀的權(quán)限
S_IWOTH 00002權(quán)限,代表其他用戶具有可寫入的權(quán)限。
S_IXOTH 00001 權(quán)限,代表其他用戶具有可執(zhí)行的權(quán)限。
返回值 若所有欲核查的權(quán)限都通過了檢查則返回0 值,表示成功,只要有一個權(quán)限被禁止則返回-1。
錯誤代碼 EEXIST 參數(shù)pathname 所指的文件已存在,卻使用了O_CREAT和O_EXCL旗標(biāo)。
EACCESS 參數(shù)pathname所指的文件不符合所要求測試的權(quán)限。
EROFS 欲測試寫入權(quán)限的文件存在于只讀文件系統(tǒng)內(nèi)。
EFAULT 參數(shù)pathname指針超出可存取內(nèi)存空間。
EINVAL 參數(shù)mode 不正確。
ENAMETOOLONG 參數(shù)pathname太長。
ENOTDIR 參數(shù)pathname不是目錄。
ENOMEM 核心內(nèi)存不足。
ELOOP 參數(shù)pathname有過多符號連接問題。
EIO I/O 存取錯誤
如:
int dev_fd;//文件描述符,失敗返回為-1。
dev_fd = open("/dev/simple",O_RDWR | O_NONBLOCK,0600);
//權(quán)限值可以不要
如果使用了O_CREATE標(biāo)志,則使用的函數(shù)為int open( const char * pathname,int flags, int mode);此時就要指定mode,用來表示文件的訪問的權(quán)限,mode的組合表示如上所述。
除了可以用以上宏來進(jìn)行“或”邏輯產(chǎn)生標(biāo)志以外,我們還可以使用自己的數(shù)字來表示,linux總共用5個數(shù)字來表示文件的各種權(quán)限,第一位表示設(shè)置用戶的ID,第二位表示設(shè)置組ID,第三位表示用戶自己的權(quán)限位,第四位表示組的權(quán)限,第五位表示其他人的權(quán)限,每個數(shù)字可以取1(執(zhí)行權(quán)限),2(寫權(quán)限),4(讀權(quán)限),0(無),或者這些值的組合。
例如,如果要創(chuàng)建一個用戶可讀,可寫,可執(zhí)行,但是組沒有權(quán)限,其他人可以讀,可以執(zhí)行的文件,并設(shè)置用戶ID,那么使用的模式是1(設(shè)置用戶ID)、0(不設(shè)置用戶ID)、7(1+2+4,讀,寫,執(zhí)行)、0(沒有權(quán)限)、5(1+4,讀,執(zhí)行),即10705,如:
Open(“test”, O_CREATE,10705)
以O_CREATE為標(biāo)志的open函數(shù)實際上實現(xiàn)了文件創(chuàng)建的功能,因此下面的函數(shù)等同create()函數(shù)。
Int open(pathname, O_CREATE |O_WRONLY,mode);
注:open函數(shù)返回的文件描述符一定是最小的未用文件描述符。
Close函數(shù)定義:
Int close(int fd)
fd:文件描述符,0為成功,-1為出錯
read函數(shù)定義:
read函數(shù)是用于將指定的文件描述符中讀出數(shù)據(jù),當(dāng)從終端設(shè)備中讀出數(shù)據(jù)時,通常一次最多讀一行。
函數(shù)原型:ssize_t read(int fd,void *buf,size_t count)
Buf:指定存儲器讀出數(shù)據(jù)的緩沖區(qū)
Count:指定讀出的字節(jié)數(shù)
函數(shù)返回值:
成功:讀到的字節(jié)數(shù)
0:已達(dá)到文件尾
-1:出錯
在讀普通文件時,若讀到要求的字節(jié)數(shù)之前已到達(dá)文件的結(jié)尾,則返回的字節(jié)數(shù)會小于希望讀出的字節(jié)數(shù)。
write函數(shù)定義:
函數(shù)是用于向打開的文件寫數(shù)據(jù),寫操作從文件的當(dāng)前位移量處開始,若磁盤已滿或超出該文件的長度,則write函數(shù)返回失敗。
函數(shù)原型:ssize_t write(int fd,void *buf,size_t count)
Buf:指定存儲器寫入數(shù)據(jù)的緩沖區(qū)
Count:指定讀出的字節(jié)數(shù)
函數(shù)返回值:
成功:已寫的字節(jié)數(shù)
-1:出錯
在寫普通文件時,寫操作從文件的當(dāng)前位移處開始。
lseek函數(shù)定義:
函數(shù)是用于在指定的文件描述符中將文件指針定位到相應(yīng)的位置。
函數(shù)原型:ssize_t lseek(int fd,off_t offset,int whence)
offset:偏移量,每一次讀寫操作所需要移動的距離,單位是字節(jié)的數(shù)量,可正可負(fù)(向前移,向后移)。
whence:SEEK_SET:當(dāng)前位置為文件指針的位置,新位置為當(dāng)前位置加上偏移量
SEEK_CUR:
SEEK_END: 當(dāng)前位置為文件的結(jié)尾,新位置為偏移量的大小加上偏移量的大小
函數(shù)返回值:
成功:文件的當(dāng)前位移
-1:出錯
Offset可取負(fù)值,即可將文件指針相對當(dāng)前位置向前移動5個字節(jié),lseek函數(shù)的返回值為文件指針相對于文件頭的位置。