1. 程式人生 > >Linux 之 POSIX 檔案 I/O 操作函式

Linux 之 POSIX 檔案 I/O 操作函式

(1)檔案描述符與檔案流轉換操作

/*成功返回檔案描述符,失敗返回-1*/
int fileno(FILE* stream);

/*成功返回檔案流,失敗返回NULL*/
FILE* fdopen(int fd,char* mode);

(2)修改檔案描述符的特殊屬性

int fcntl(int fd,int cmd,...);

第一個引數為檔案描述符,第二個引數cmd為響應操作,失敗返回-1,常用命令如下:

#define  F_DUPFD       0   /*複製檔案描述符,ag:fcntl(fd,F_DUPFD)*/
#define  F_GETFD       1   /*獲取檔案描述符標誌*/
#define F_SETFD 2 /*設定檔案描述符標誌*/ #define F_GETFL 3 /*獲取檔案狀態,ag:fcntl(fd,F_GETFL,0)*/ #define F_SETFL 4 /*設定檔案狀態*/

(3)同步核心緩衝區sync、fsync、fdatasync

#include <unistd.h>
void sync(void);
int fsync(int fd);
int fdatasync(int fd);

函式sync()始終成功,但只是將修改過的塊的快取排入寫佇列,並不等待 實際I/O操作結束。系統守護程序會週期性的(一般30s)會呼叫一次sync()函式,從而保證系統定期重新整理核心快取。
函式fsync()函式則等待實際I/O結束才返回,從而確保修改過的塊立即寫到硬碟上,成功返回0,否則返回-1。
函式fdatasync()只是更新硬碟檔案內容,如果沒有必要,並不更新元資料,即檔案的屬性(長度、上次修改時間等),成功返回0,否則返回-1。

(4)鎖定/解鎖檔案

// from /usr/include/sys/file.h
int flock(int fd,int operation);

函式的第一個引數為欲鎖定/解鎖的檔案描述符,第二個引數為操作命令:

// from /usr/include/sys/file.h
#define  LOCK_SH  1 /* 共享鎖:多個程序可同時對一個檔案進行共享讀操作,但不能排他寫鎖定*/
#define  LOCK_EX  2 /* 排他鎖:任意兩個程序不能同時操作同一個檔案 */
#define  LOCK_UN  8 /* 解鎖:解除檔案鎖定狀態 */
#define  LOC_NB   4 /* 無法建立鎖時,立即返回 */

(5)對映檔案到記憶體

#include <sys/mman.h>
void* mmap(void* start,size_t length,int prot,int flags,int fd,off_t offset);

該函式將程序的虛擬地址空間與檔案fd建立對映關係,這樣程序就可以像訪問記憶體一樣,訪問檔案了,各引數說明如下:
start: 對映記憶體的首地址,必須為記憶體頁大小(PAGE_SIZE)的整數倍,當然也可以置為NULL,表示由系統分配。

length:對映的檔案長度

prot: 對映的記憶體許可權,但不得與檔案的開啟許可權衝突,該引數有以下選項的組合:
PORT_READ: 允許讀該記憶體
PORT_WRITE: 允許寫該記憶體
PORT_EXEC: 允許執行該記憶體段
PORT_NONE: 該記憶體段不能被訪問

flags:控制程式對該記憶體段修改時,造成的影響範圍,常用的選項如下:
MAP_PRIVATE: 記憶體是私有的,對他的修改只在區域性範圍內有效,其他程序不可見。
MAP_SHARED: 記憶體是共享的,某程序對該段記憶體空間的更新對其他程序是可見的

fd: 對映檔案的檔案描述符

offset:對映內容在該檔案的起始偏移位置

此外,一般mmap()函式常與munmap()、msync()結合一起使用,函式宣告如下:

int munmap(void* start,size_t length);   /* 解除對映 */
int msync(const void* start,length,int flags);/* 立即將記憶體修改內容寫入檔案 */

其中start為記憶體開始位置,length為長度,flags選項如下:
MS_ASYNC: 請核心儘快將修改寫入檔案
MS_SYNC : 在此函式返回前,將修改寫入到檔案
MS_INVALIDATE:核心自行決定是否立即寫入

(6)截短檔案

#include <unistd.h>
int ftruncate(int fd, off_t length);

將檔案大小改變為引數length指定的大小,如果原來的檔案大小比引數length大,則超過的部分會被刪除,如果原來的檔案大小比引數length小,則檔案將被擴充套件,與lseek系統呼叫類似,檔案的擴充套件部分將以0填充。如果檔案的大小被改變了,則檔案的st_time 和st_ctime將會更新。

(7)檔案屬性獲取

// from /usr/include/sys/stat.h
int stat(const char* filename,struct stat* buf);   //普通檔案(傳入絕對路徑或相對路徑)
int fstat(int fd,struct stat* buf);                //普通檔案(傳入已開啟的fd)
int lstat(const char* filename,struct stat* buf);  //符號連結檔案

不同情形選擇不同函式,作用都是獲取指定檔案的屬性,並儲存在結構體buf中。其中結構體struct stat定義如下:

struct stat
{
    unsigned short   st_dev;              //裝置號
    unsigned short   _pad1;              
    unsigned long    st_ino;              //檔案inode值
    unsigned short   st_mode;             //檔案型別及許可權
    unsigned short   st_nlink;            //硬體連線數
    unsigned short   st_uid;              //使用者ID
    unsigned short   st_gid;              //使用者組ID
    unsigned short   st_rdev;             //裝置號
    unsigned short   _pad2;
    unsigned long    st_size;             //檔案大小
    unsigned long    st_biksize;          //資料塊大小
    unsigned long    st_blocks;           //資料塊數量
    unsigned long    st_atime;            //最後一次訪問時間
    unsigned long    _unused1;
    unsigned long    st_mtime;            //最後一次修改時間
    unsigned long    _unused2;
    unsigned long    st_ctime;            //最後一次改變屬性時間
    unsigned long    _unused3;
    unsigned long    _unused4;
    unsigned long    _unused5;
}