第一層、虛擬文件系統(VFS)node
第二層、各類不一樣的具體的文件系統緩存
VFS就是把各類具體的文件系統的公共部分抽取出來,造成一個抽象層,是系統內核的一部分。bash
查看系統支持哪些文件系統:異步
# cat /proc/filesystems
VFS的主要目的在於引入了一個通用的文件模型(Common File Model),這個模型的核心是4個對象類型,即超級塊對象(Superblock Object)、索引節點對象(Inode Object)、文件對象(File Object)和目錄項對象(Dentry Object)。socket
一、超級塊對象函數
用來描述整個文件系統信息。VFS超級塊是由各類具體的文件系統在安裝時創建的,只存在於內存中。ui
超級塊對象經過alloc_super()函數建立並初始化。在文件系統安裝時,內核會調用該函數以便從磁盤讀取文件系統超級塊,而且將其信息填充到內存的超級塊對象中。spa
二、索引節點對象指針
文件系統中處理文件所須要的信息都放在索引節點對象裏。文件名能夠隨時更改,可是索引節點是惟一的。code
類型:
inode有一個惟一的i_ino節點號。每一個文件都有一個文件主,指文件的建立者,可改變。每一個用戶都有用戶組,所以inode結構中應有i_uid、i_gid,指明身份權限。
inode中還有兩個設備號i_dev和i_rdev,分別表明主設備號和從設備號。
節點的管理:
5.1.三、Linux下的設備文件
字符設備:以字節爲單位逐個進行I/O操做的設備。不支持隨機訪問。
塊設備:利用一塊系統內存做爲緩衝區。先緩衝區,後實際I/O操做。
5.2.一、不帶緩存的文件I/O操做
一、文件描述符,非負整數。
二、open 和 close
#include <fcntl.h> int open(const char *pathname, /*被打開的文件名*/ const char flags, /*文件打開的方式*/ int perms) /*被打開文件的存取權限,八進制*/ // 成功:返回文件描述符 // 失敗:-1
#include <unistd.h> int close(int fd); /*fd爲文件描述符*/ // 成功:0 // 出錯:-1
// 調用示例 int fd = open("/tmp/hello.c", O_WRONLY | O_CREATE | O_TRUNC, 0666); close(fd);
三、read、write和lseek
#include <unistd.h> size_t read/write (int fd, /*文件描述符*/ void *buf, /*緩衝區*/ size_t count); /*字節數*/ // 成功:實際字節數 // 已達文件尾(讀):0 // 出錯:1
#include <unistd.h> #include <sys/types.h> off_t lseek(int fd, /*描述符*/ off_t offset, /*偏移量,單位是字節,可正可負*/ int whence); /*基點*/ // 成功:文件的當前位置 // 出錯:-1
char buf_write[] = "abcdefg"; char buf_read[10]; int fd = open("/tmp/hello.c", O_CREAT | O_TRUNC | O_RDWR, 0666); int len = strlen(buf_write) + 1; int size = write(fd, buf_write, len); lseek(fd, 0, SEEK_SET); size = read(fd, buf_read, len);
四、fcntl
複製現有描述符,得到/設置文件描述符標記,得到/設置文件狀態標記。得到/設置異步I/O全部權及得到/設置記錄鎖。
文件鎖包括建議性鎖和強制性鎖。
鎖函數,lockf 和 fcntl,lockf施加建議性鎖,而fcntl不只能夠施加建議性鎖,還能夠施增強制性鎖。還能夠實現記錄鎖。
記錄鎖:
#include <sys/types.h> #include <unistd.h> #include <fcntl.h> int fcntl(int fd, /*文件描述符*/ int cmd, /*不一樣的命令*/ struct flock *lock); /*設置記錄鎖的具體狀態*/ // 成功:0 // 出錯:-1
/*lock結構*/ struct flock { short l_type; off_t l_start; short l_whence; off_t l_len; pid_t l_pid; }
加鎖整個文件經常使用的方法是將l_start說明爲0,l_where說明爲SEEK_SET,l_len說明爲0。
五、select
fcntl函數解決了文件的共享問題,接下來處理I/O多路複用。
I/O處理模型:
#include <sys/types.h> #include <sys/time.h> #include <unistd.h> int select(int numfds, /*須要檢查的最大的文件描述符+1*/ fd_set * readfds, /*監視的讀文件描述符集合*/ fd_set * writefds, /*監視的寫文件描述符集合*/ fd_set * exeptfds, /*監視的異常處理文件描述符集合*/ struct timeval *timeout); /*等待時間*/ // 成功:已就緒的文件描述符的數量 // 出錯:-1
struct timeval { long tv_sec; long tv_usec; }
前述文件的I/O都是基於文件描述符的不帶緩存的操做。標準I/O都是基於流的,符合ANSI C的操做。
又稱高級磁盤I/O,是在文件I/O的基礎上進行了封裝。
一、FILE指針
標準I/O爲每一個打開的文件在內存中開闢一個區域,用來存放文件的相關信息。這些信息被保存在一個由系統定義的結構體類型FILE中。在標準I/O中,流(stream)用FILE *來描述,全部的操做都是圍繞流來進行的。
in <stdio.h> typedef struct _IO_FILE FILE; in <libio.h> struct _IO_FILE { int _flags; ... int _fileno; ... };
標準I/O庫中預約義了3個流:標準輸入(stdin)、標準輸出(stdout)和標準錯誤(stderr)。當一個程序執行時,系統自動打開這3個流,而且能夠在程序中直接使用。
二、打開流
打開文件有3個標準函數,分別爲fopen、fdopen和freopen。
fopen指定打開文件的路徑和模式;fdopen指定打開的文件描述符和模式;freopen還可指定特定的I/O流。
#include <stdio.h> FILE * fopen(const char * path, const char * mode); FILE * fdopen(int fd, const char * mode); FILE * freopen(const char * path, const char * mode, FILE * stream); // 成功:指向FILE的指針 // 失敗:NULL
#include <stdio.h> int fclose(FILE * stream); // 成功:0 // 失敗:EOF(-1)
四、按字符讀/寫文件
#include <stdio.h> int fgetc(FILE * stream); int getc(FILE * stream); int getchar(void); int fputc(int c, FILE * stream); int putc(int c, FILE * stream); int putchar(int c); // 成功:字符 // 失敗:EOF
五、按行讀/寫文件
#include <stdio.h> char *fgets(char *s, int n, FILE *stream); int fputs(const char *s, FILE *stream); int puts(const char *s); // fgets 成功:緩衝區地址,失敗:NULL // fputs 成功:字符串長度,失敗:EOF // puts 成功:字符串長度+1,失敗:EOF
六、按指定格式讀/寫文件
一般處理二進制文件。
#include <stdio.h> size_t fread/fwrite(void * ptr, /*緩衝區*/ size_t size, /*讀取的記錄大小*/ size_t nmemb, /*讀取的記錄數*/ FILE * stream); /*文件流*/ // 成功:實際對象數量 // 失敗:EOF
七、刷新流
#include <stdio.h> int fflush(FILE * stream); // 成功:0 // 失敗:-1
八、文件定位
#include <stdio.h> void rewind(FILE * stream); int fseek(FILE * stream, long offset, int whence); long ftell(FILE * stream); // fseek 成功:0,失敗:-1 // ftell 成功:文件當前位置,失敗:-1L
stat/fstat/lstat函數
#include <sys/types/h> #include <sys/stat.h> #include <unistd.h> int stat(const char *filename, struct stat *buf); int fstat(int fd, struct stat *buf); int lstat(const char *filename, struct stat *buf); /*支持符號連接*/ struct stat { dev_t st_dev; // 文件所在的設備名稱 ino_v st_ino; // 文件對應的i節點號 mode_t st_mode; // 文件模式 nlink_t st_nlink; // 硬連接個數 uid_t st_uid; // 文件建立者ID gid_t st_gid; // 文件建立者組ID dev_t st_rdev; // 設備類型 off_t st_size; // 文件大小 blksize_t st_blksize; // 塊大小 blkcnt_t st_blocks; // 塊個數 time_t st_atime; // 上次訪問時間 time_t st_mtime; // 上次修改時間 time_t st_ctime; // 上次改變狀態時間 } st_mode // 成功:0 // 失敗:-1,並設置errno
struct stat buf; fstat("./data", &buf); switch(buf.st_mode & S_IFMT) { case S_IFREG: printf("regular file\n"); break; case S_IFDIR: printf("directory\n"); break; default: printf("other file types\n); break; }
chmod/fchmod函數
#include <sys/types.h> #include <sys/stat.h> int chmod(const char *filename, mod_t mode); int fchmod(int fd, mode_t mode); // 成功:0 // 失敗:-1,並設置errno
chmod("./data", S_IRWXU|S_IRGRP|S_IWGRP|S_IROTH);
mkdir函數
#include <sys/stat.h> int mkdir(const char *filename, mode_t mode); // 成功:0 // 失敗:-1,並設置errno mkdir("mydir", 0755);
#include <unistd.h> int link(const char *path1, const char *path2); /*建立硬連接path2*/ int symlink(const char *path1, const char *path2); /*建立符號連接path2*/ // 成功:0 // 失敗:-1,並設置errno link("./data", "./data1"); symlink("./data", "./data2");
unlink/remove函數
#include <unistd.h> int unlink(const char *filename); int remove(const char *filename); // 成功:0 // 失敗:-1,並設置errno unlink("./data");
5.3.八、重命名文件
#include <unistd.h> int rename(const char *old, const char *new); // 成功:0 // 失敗:-1,並設置errno rename("./data_old", "./data_new");