Unix系統中主要的文件操作包括:
unbuffered IO和standard I/O相對應,後面的章節我們會討論這兩者的區別。
在討論open函數的時候,會引入原子操作,多進程通信(共享文件描述符)和內核相關的數據結構。
對應內核來說,每一個打開的文件都對應一個非負整數。
有三個特殊的文件描述符:
對於較新的內核來說(Linux3.2.0,Solaris10等),文件描述符的數量並沒有明確的限制,受限於內存的大小。
相關閱讀:Unix環境高級編程第二版讀書筆記
UNIX環境高級編程中文第二版PDF高清版 下載地址 http://www.linuxidc.net/thread-2063-1-1.html
UNIX高級環境編程(第二版)源代碼下載:http://www.linuxidc.net/thread-2069-1-1.html
常用的文件操作函數包括:open,read,write,lseek,close
函數聲明:
#include <fcntl.h> int open (const char *path, int oflag, … /* mode_t mode */); int openat (int fd, const char *path, int oflag, … /* mode_t mode */);
返回值:
OK:文件描述符(非負整數)
Error:-1
注:參數列表中,“...”表示不同的系統和標准中,該處的參數可能不相同。
參數說明:
path:文件名
oflag:打開創建文件的屬性。
下面有五個必選的oflag參數值,這五個值有切只能選一個。另外還有若干個可選參數值,可以自行百度。
細節說明:
由open和openat返回的文件描述符保證為未使用的最小的文件描述。有的應用利用這一特性,先關閉標准輸入描述符0,就可以在標准輸入描述0上打開文件。
參數fd可以區分open和openat函數。其取值有三種可能:
openat函數解決了兩個問題:
這裡介紹一下TOCTTOU錯誤。該類錯誤指的是,程序是非常脆弱的(vulnerable)如果該程序調用了兩個文件相關的函數,第二個函數依賴於第一個函數的結果。因為兩個函數是非原子操作,被操作的文件可能被兩個函數輪流操作(線程切換),導致第一個函數的結果出錯,從而程序出錯。
函數聲明:
#include <fcntl.h> int creat(const char* path, mode_t mode);
返回值:
creat函數相當於下面這樣調用open函數
open (path, O_WEONLY | O_CREAT | O_TRUNC, mode);
creat有一點不方便,因為它打開的文件描述符是只讀的,如果希望寫入之後讀回,需要依次調用creat、close和open,才能實現。
因此,在這種場景下,一個更好的打開文件的方法是像下面這樣調用open函數:
open (path, O_RDWR | O_CREAT | O_TRUNC, mode);
函數聲明:
#include <unistd.h> int close(int fd);
返回值:
關閉一個文件會釋放所有當前進程加在該文件上的記錄鎖。
每一個打開的文件都有一個”當前文件偏移量(current file offset)“,該偏移量是一個非負整數,記錄了從文件開始到當前位置的字節數。
函數聲明:
#include <unistd.h> off_t lseek(int fd, off_t offset, int whence);
參數說明:
offset的作用取決於參數whence的值:
細節說明:
獲取當前文件偏移量的方法:
1 off_t currpos; 2 3 currpos = lseek(fd, 0, SEEK_CUR);
lseek只記錄當前文件在內核中的偏移量,並不會引起任何的IO操作。返回的offset將會在後面的read或write函數中使用。
偏移量可以比當前文件的長度大,這時,再調用write函數時,將擴展該文件的長度。這樣的操作相當於在文件中建了一個洞,該洞范圍內讀時返回0。
使用od命令可以看到文件中的hole
函數聲明:
#include <unistd.h> ssize_t read(int fd, void *buf, size_t nbytes);
返回值:
細節說明:
在一些情況下,函數返回的字節數比指定的讀入字節數要小,多數是因為讀到了文件末尾,或者指定的讀取位置中包含的字節數小於指定的讀入字節數,這時,read返回的為可讀到的字節數。
函數聲明:
#include <unistd.h> ssize_t write (int fd, const void *buf, size_t nbytes);
返回值:
返回值總是等於參數nbytes的值,否則就會報錯。
對於常規的文件來說,寫操作總是從當前文件偏移量開始。
簡單地介紹了一下常用的文件IO操作,並介紹了一些使用上的細節,比較常規。
下一篇講介紹更多文件IO的特性,包括:dup,fcntl,sync,fsync和ioctl函數。。
好久沒寫博客了,又第一次用mac下的一個博客軟件寫,不太熟悉,所以寫的比較簡單,以後會寫的更努力。
參考資料:
《Advanced Programming in the UNIX Envinronment 3rd》
更多詳情見請繼續閱讀下一頁的精彩內容: http://www.linuxidc.com/Linux/2015-02/113520p2.htm