知識點4【文件的阻塞特性】
文件描述符 默認為 阻塞?的
比如:我們讀取文件數據的時候,如果文件緩沖區沒有數據,就需要等待數據的到來,這就是阻塞
當然寫入的時候,如果發現緩沖區是滿的,也需要等待刷新緩沖區,才可寫入,這也是阻塞
注意:阻塞和非阻塞都是對文件而言的,并不是read和write的屬性
下面 我來介紹兩種設置文件非阻塞的方法:
- 通過open函數再打開文件的時候,設置文件為非阻塞
注意:文件描述符 事先不存在?才使用open的方法
案例1:open打開文件,默認為阻塞特性
這里補充一個知識點,當我們需要 打開終端時,終端的目錄是 /dev/tty,下面我們在Linux中查看一下
好了現在我們實現從終端中讀數據
代碼演示
- 帶有阻塞特性
int?main(int?argc, char?const?*argv[]){//打開文件int?fd?=?open("/dev/tty",O_RDONLY?|?O_NONBLOCK);if(fd?<?0){perror("open");return?0;}//讀取文件到數組printf("非阻塞特性展示\n");printf("請輸入字符數據\n");char?buf[128] =?"";read(fd,buf,sizeof(buf));printf("buf = %s\n",buf);//關閉文件close(fd);return?0;}
可以看到有一個等待的過程
- 非阻塞特性
僅展示主要代碼
int?fd?=?open("/dev/tty",O_RDONLY?|?O_NONBLOCK);
- 使用fcntl函數在文件打開后設置文件為非阻塞
文件描述符 事先存在?
fcntl函數介紹
int fcntl(int fd,int cmd,…/*arg*/)
功能介紹
改變已打開文件描述符的文件性質,針對文件描述符提供控制
參數
fd:文件描述符
cmd:操作方式
arg:cmd不同,arg會不同
返回值
成功:不同的cmd,會有不同
失敗:-1
cmd:
fcntl函數有5種功能:
1) 復制一個現有的描述符(cmd=F_DUPFD)
2) 獲得/設置文件描述符標記(cmd=F_GETFD或F_SETFD)
3) 獲得/設置文件狀態標記(cmd=F_GETFL或F_SETFL)
4) 獲得/設置異步I/O所有權(cmd=F_GETOWN或F_SETOWN)
5) 獲得/設置記錄鎖(cmd=F_GETLK, F_SETLK或F_SETLKW)
這里我們設置阻塞特性主要使用 cmd=F_GETFL或F_SETFL
但這里我提一下 文件狀態標記和文件描述符標記是不同的,大家可以自行使用ChatGPT搜索區別,若仍有疑問可以評論留言
設置一個存在的文件描述符的阻塞特性的步驟
- fcntl先得到的文件描述符的狀態標記
- 修改文件的狀態標記
- 將修改后的狀態標記應用到文件描述符上
代碼演示
#include?<stdio.h>#include?<sys/types.h>#include?<sys/stat.h>#include?<fcntl.h>#include?<unistd.h>int?main(int?argc, char?const?*argv[]){//提取文件狀態標記int?flag?=?fcntl(0,F_GETFL);//處理文件狀態標記flag?=?flag?|?O_NONBLOCK;//應用文件狀態標記fcntl(0,F_SETFL,flag);//阻塞特性驗證char?buf[128] =?"";printf("請輸入數據\n");read(0,buf,sizeof(buf));printf("buf = %s\n",buf);return?0;}
代碼運行結果
知識點5【獲取文件狀態】
int stat(const char *path,struct stat *buf);
int lstat(const char *path,struct stat *buf);
思想補充
我們能知道如果要想要函數內部修改函數外部的值,參數為指針類型
我們反過來也許知道
如果函數參數是指針類型,我們就需要知道這個函數需要是對其進行賦值操作的
stat和lstat的區別
概念復習
這里幫大家復習一個概念
鏈接方式分為軟鏈接和硬鏈接?
軟連接:類似于快捷方式,操作其鏈接文件數據,源文件數據也會改變,但是如果源文件被刪除,鏈接文件不能正常使用
軟鏈接:類似于快捷方式,操作其鏈接文件數據,源文件數據也會改變,但是如果源文件被刪除,鏈接文件不能正常使用
硬鏈接:類似于文件的拷貝(不是簡單的拷貝,有鏈接),操作其鏈接文件數據,源文件數據也會改變,但是如果源文件被刪除,鏈接文件能正常使用
區別
當我們查看鏈接文件的文件信息的時候
stat:會獲得源文件的文件信息
lstat:會獲得鏈接文件的文件信息
查看源文件的文件信息的時候,沒有區別,最好使用stat
這兩個函數的參數,返回值都一樣
函數介紹
參數
path:文件的路徑及文件名
buf:保存文件信息的結構體
返回值
成功:0
失敗:-1
案例1:獲取文件的屬性、大小
這里主要介紹兩種文件模式的判斷方式
- 使用宏,這里 的都是宏,我們只需要使用宏函數可以直接判斷
- 使用按位與的操作
if((s.st_mode & S_IRWXU)?== S_IRWXU)
注意:這里的()必須加,優先級問題
代碼演示
#include?<stdio.h>#include?<sys/types.h>#include?<sys/stat.h>#include?<unistd.h>int?main(int?argc, char?const?*argv[]){struct?stat?s;stat("./text.txt",&s);//方式一判斷文件類型if(S_ISDIR(s.st_mode)){printf("text是一個目錄\n");}//方式二判斷文件類型else?if((s.st_mode?&?S_IFREG) ==?S_IFREG){printf("text是一個普通文件\n");}//文件權限 有上面的man 2 stat 可知 判斷只能使用 方式二if((s.st_mode?&?S_IRUSR) ==?S_IRUSR){printf("text文件所有者可讀\n");}if((s.st_mode?&?S_IWUSR) ==?S_IWUSR){printf("text文件所有者可寫\n");}if((s.st_mode?&?S_IXUSR) ==?S_IXUSR){printf("text文件所有者可執行\n");}return?0;}
代碼運行結果
知識點6【文件目錄操作函數】(重點)
常用文件目錄操作函數:opendir readdir closedir ?下面詳細介紹
- 得到文件目錄的句柄 opendir
句柄
句柄就是結構體指針
句柄我們在文件操作中也用到過,比如我們得到的FILE*就是一個文件句柄。FILE * 是一個結構體指針,結構體中存儲的是文件信息
在文件目錄的介紹中,我們先函數介紹功能,然后通過一個整體的項目帶大家了解其功能
函數介紹
DIR *opendir(const char *name)
功能
打開一個目錄
參數
name:目錄名
返回值
成功:返回指向該目錄的 結構體的指針(目錄句柄)
失敗:NULL
- 讀取目錄readdir
函數介紹
struct dirent *readdir(DIR *dirp)
功能介紹
讀取目錄,調用一次只能讀取一個文件
參數
dirp:opendir的返回值
返回值
成功:目錄結構體指針
失敗:NULL
struct dirent 結構體介紹
d_type相關數據
- 關閉目錄closedir
函數介紹
int close(DIR *dirp)
功能介紹
讀取目錄,調用一次只能讀取一個文件
參數
dirp:opendir的返回值
返回值
成功:0
失敗:1
代碼演示
#include <sys/types.h>
#include <dirent.h>
#include <stdio.h>
#include <string.h>
void readDir(char *name);
int main(int argc, char const *argv[])
{readDir("..");return 0;
}/*** 讀取一個目錄中的內容** @param const char *name 目錄名* @return 添加成功返回 1,否則返回 0*/
void readDir(char *name)
{//打開一個文件夾,并判斷打開文件是否有效DIR *dirp = opendir(name);//讀取文件夾 循環struct dirent *read_dir; while(read_dir = readdir(dirp)){if((read_dir->d_type & DT_REG) == DT_REG){printf("%s是一個普通文件\n",read_dir->d_name);}else if((read_dir->d_type & DT_DIR) == DT_DIR){//測試時 發現文件夾中有.. 和 . 文件夾,因此去掉if (strcmp(read_dir->d_name, ".") == 0 || strcmp(read_dir->d_name, "..") == 0) {continue; // 跳過本次循環}//處理遞歸目標目錄char dir_name[512] = "";sprintf(dir_name,"%s/%s",name,read_dir->d_name);//printf("dir_name = %s\n",dir_name);printf("\n%s是一個文件夾,它的內部文件為:\n",read_dir->d_name);readDir(dir_name);}}//關閉目錄closedir(dirp);
}
結束
代碼重在練習!
代碼重在練習!
代碼重在練習!
今天的分享就到此結束了,希望對你有所幫助,如果你喜歡我的分享,請點贊收藏夾關注,謝謝大家!!!