Linux系統調用 - open

open() 系統調用很有可能是Linux開發者用到的第一個系統調用,它打開一個指定目錄上的文件或設備,必要的時候會創建一個。

函數原型:int open(const char *pathname, int flags, ...);

其中的可選參數是在創建文件的時候指定新文件的模式。flags參數應該至少包含一個訪問模式:O_RDONLY,O_WRONLY或者O_RDWR,分別表示文件是隻讀的,只寫的,或可讀可寫的。

該函數如果執行成功,它會返回系統中可用的最小的文件描述符整數來標識操作的文件。例如,新運行的程序會默認打開標準輸入,標準輸出和標準錯誤輸出三個文件描述符,分別佔用0,1,2三個整數。所以,程序中第一次成功調用open之後獲得的文件描述符通常是從3開始一次編號的。如果首先關閉了標準輸出,再調用open,那麼得到的文件描述符就會是1。

常見的用法:

打開一個文件用於讀取內容:int fd = open("/tmp/readfile.txt", O_RDONLY);

打開一個文件寫入新的內容,int fd = open("/tmp/writefile.txt", O_WRONLY);

打開一個文件向裏面追加內容:int fd = open("/tmp/appendfile.txt", O_WRONLY | O_APPEND);

 

可選的控制選項的詳細解釋如下:

O_APPEND:以該模式打開文件之後,文件的當前偏移指針會移動到文件的末尾。需要注意的是,如果有多個進程同時以這種模式向NFS文件系統中的文件寫入數據,可能會造成文件的損壞,因爲NFS文件系統是不支持文件內容追加的,所以內核不得不用另外的方式模擬這種行爲,但是這是會有一種無法避免的競態條件。

O_ASYNC:設置此標誌之後,打開的文件描述符準備好輸入或輸出時,會產生SIGIO信號。這個標誌只能給終端,僞終端,套接字,管道或者命名管道使用。但是目前在open中設置這個標誌好像是沒有作用,需要打開文件之後用fcntl設置該標誌。

O_CLOEXEC:這個標誌是從Linux 2.6.23版本的內核之後纔有的。設置這個標誌之後,在當前進程執行execve系列系統調用執行一個新程序的時候,這個文件會被關閉。這個標誌的意義在於,當execve()成功執行的時候,原來程序中已經打開的文件都應該被關閉,但是execve()也是有可能會失敗的,當由於某種原因execve()執行失敗的時候,打開的文件描述符應該保持在打開狀態,而且文件偏移位置也應該保持原樣。讓應用程序來維護這些狀態太過於複雜,甚至基本上是不可能的。所以,需要用這個標誌來讓內核幫助應用做這個事情。最早的時候,這個標誌只能在fcntl()系統調用中設置給一個已經打開的文件描述符。但是這樣分兩步的操作在多線程程序中會有一種無法避免的競態問題,比如,當有一個線程打開文件,但是還沒設置O_CLOEXEC標誌之前,另外一個線程就執行了fork()+execve()。這種情況下,這個新打開的文件就沒有機會關閉了。所以,就把對這個標誌的設置放在了open中,保證這一連串操作是原子的,就不會有這種棘手的競態條件出現了。
              

O_CREAT:這個標誌表示如果文件不存在,就創建一個新文件。當指定這個標誌打開文件的時候,還需要設置新文件的訪問模式,可用的訪問模式是一組用戶,組和其他組用戶的讀寫執行權限標誌的組合,包括:S_IRWXU,S_IRUSR,S_IWUSR,S_IXUSR,S_IRWXG,S_IRGRP,S_IWGRP,S_IXGRP,S_IRWXO,S_IROTH,S_IWOTH,S_IXOTH。各標誌的意義不言自明,就不用多說了。

O_DIRECT: 設置了這個標誌的文件的讀寫在內核中不會有讀寫緩衝區,而是直接同步地從用戶控件buffer刷新到磁盤或相反。這個標誌是在Linux 2.4.10開始加入的,這個標誌會引起讀寫性能的下降,所以在默認情況下是關閉的。這個標誌不在POSIX標準中,要使用它需要定義_GNU_SOURCE宏。

這個標誌的作者認爲它對一些自己管理數據緩存的應用是有用的,例如一些數據庫管理程序。但是口無遮攔的Linus先生卻並不這麼認爲,他說:“O_DIRECT有個一直困擾我的問題是它整個接口都很愚蠢,它可能是某個被嚴重精神藥物控制的瘋狂的猴子設計的。”(The thing that has always disturbed me about O_DIRECT is that the whole interface is just stupid, and was probably designed by a deranged monkey on some serious mind controlling substances.)他這麼說也並不是沒有道理,使用這個標誌的時候有諸多需要注意的事項,否則可能會產生並不希望看到的結果。詳情請參考open的幫助手冊。

O_DIRECTORY:指定要打開一個目錄,如果不是目錄會打開失敗。

O_EXCL:這個標誌與O_CREATE一起使用的時候,如果文件已經存在,open()調用會失敗。如果要在在NFS文件系統上使用這個標誌,需要至少2.6或之後的內核,以及NFSv3及之後的文件系統版本。

O_LARGEFILE:允許在32位系統上打開一個超過2G的文件。在內核數據結構中,標記文件大小的字段是個32位有符號整形,所以只能表示不超過2G的大小,考慮到文件和目錄在內核中使用相同的數據結構,其中還有個目錄使用的32位整形數,普通的文件肯定不會用到這個字段,所以,當設置了大文件標記之後,內核就用這個目錄使用的32位整形與文件大小字段的32位整形合併在一起標記文件的大小。

O_NOATIME:打開文件是不更新文件的訪問時間信息。這個標誌對一些後臺歸檔備份程序特別有用。因爲訪問時間等文件元信息通常會存放在與文件內容不同的磁盤頁面上,所以,設置了這個標誌之後,可以減少一次尋道操作,從而爲索引或備份程序帶來更好的性能。這個標誌是在Linux 2.6.8版本引入的。但是這個標誌對NFS上的文件是無效的,因爲在NFS上,是由文件服務器維護訪問時間的。

O_NOCTTY:如果打開了一個終端設備,不讓這個終端成爲當前進程的控制終端。

O_NOFOLLOW:如果目錄名指向的是一個符號鏈接文件,那麼不解引用去打開被鏈接的文件,打開會失敗。從內核2.1.126開始支持這個標誌。

O_NONBLOCK 或 O_NDELAY:以非阻塞的方式打開文件。

O_SYNC:以同步方式打開文件,在設置了該標誌的文件上的write操作會一直阻塞進程,知道數據已經真正寫入到物理存儲設備上才返回。在一些數據可靠性非常重要的應用中會使用這個標誌。

O_TRUNC:如果文件已經存在,並且是個普通文件,並且以可寫的方式打開,那麼這個標誌會把文件內容清空。如果打開的文件是命名管道或者是一個設備文件,這個標誌會被忽略。

 

如果open()系統調用執行失敗,會返回-1,同時會把errno設置爲錯誤原因,errno的含義請參考errno的參考手冊。

 

另外需要注意的是,訪問模式標誌:O_RDONLY, O_WRONLY,O_RDWR雖然可以與其他的標誌按位或,但是他們三個之間不能這樣做,因爲它們三個分別被定義成了整數值0,1,2,而不是每個標誌佔用一個位,所以O_RDONLY | O_WRONLY並不等於O_RDWR。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章