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;
}