檔案描述符與FILE概念介紹
1. 文件描述符(重點)
在Linux系統中一切皆可以看成是文件,文件又可分為:普通文件、目錄文件、連結文件和設備文件。文件描述符(file descriptor)是內核為了高效管理已被打開的文件所創建的索引,其是一個非負整數(通常是小整數),用於指代被打開的文件,所有執行I/O操作的系統呼叫都通過檔案描述符。程式剛啟動的時候,0是標準輸入,1是標準輸出,2是標準錯誤。如果此時去開啟一個新的文件,它的文件描述會是3。
1.1概念介紹
檔案描述子的運算(如: open(),creat(),close(),read()))返回的是一個檔案描述子,它是int類型的整數,即fd,其本質是檔案描述子表中的下標,它起到一個索引的作用,進程透過PCB中的檔案描述子表找到該fd所所指的文件指標filp。每個進程在PCB(Process Control Block)即進程控制塊中都保存著一份文件描述符表,而文件描述符就是這個表的索引,文件描述表中每個表項都有一個指向已打開文件的指標; 已開啟的檔案在核心中以file
結構體表示,檔案描述子表中的指標指向file
結構體。每打開一個文件,fd預設從最小的未被使用的下標開始分配。文件描述符的缺點:不能移植到UNIX以外的系統上去,也不直觀。
下面畫張圖來表示它們之間的關係:
而每個檔案中又主要包含以下這些資訊:
1.2圖表解釋
在file
結構體中維護File Status Flag(file
結構體的成員f_flags
)和目前讀寫位置(file
結構體的成員f_pos
)。在上圖中,進程1和進程2都開啟相同文件,但對應不同的file
結構體,因此可以有不同的File Status Flag和讀寫位置。 file
結構體中比較重要的成員還有f_count
,表示引用數數(Reference Count),後面我們會講到,dup
、fork
等系統呼叫會導致多個檔案描述子指向同一個file
結構體,例如有fd1
和fd2
都引用同一個 file
結構體,那麼它的引用計數就是2,當close(fd1)
時並不會釋放file
結構體,而只是把引用計數減到1,如果再close(fd2)
,引用計數就會減少到0同時釋放file
結構體,這才真的關閉了檔案。
每個file
結構體都指向一個file_operations
結構體,這個結構體的成員都是函數指針,指向實作各種檔案操作的核心函數。例如在使用者程式中read
一個檔案描述符,read
#透過系統呼叫進入內核,然後找到這個檔案描述符所指向的file
結構體,找到file
結構體所指向的file_operations
結構體,呼叫它的read
成員所指向的核心函數以完成使用者請求。在使用者程式中呼叫lseek
、read
、write
、ioctl
、open
等函數,最後都由核心呼叫file_operations
的各成員所指向的核心函數完成使用者請求。 file_operations
結構體中的release
成員用來完成使用者程式的close
請求,之所以叫release
而不叫 close
是因為它不一定真的關閉文件,而是減少引用計數,只有引用計數減到0才關閉文件。對於同一個檔案系統上開啟的常規檔案來說,read
、write
等檔案操作的步驟和方法應該是一樣的,呼叫的函數應該是相同的,所以圖中的三個開啟檔案的file
結構體指向同一個file_operations
結構體。如果開啟一個字元設備文件,那麼它的read
、write
操作肯定和常規文件不一樣,不是讀寫磁碟的資料塊而是讀寫硬體設備,所以file
結構體應該指向不同的file_operations
結構體,其中的各種檔案操作函數由該裝置的驅動程式實作。
每個file
結構體都有一個指向dentry
結構體的指針,「dentry」是directory entry(目錄項目)的縮寫。我們傳給open
、stat
等函數的參數的是路徑,例如/home/akaedu/a
,需要根據路徑找到檔案的inode。為了減少讀盤次數,核心快取了目錄的樹狀結構,稱為dentry cache,其中每個節點是一個dentry
結構體,只要沿著路徑各部分的dentry搜尋即可,從根目錄/
找到home
目錄,然後找到akaedu
目錄,然後找到檔案a
。 dentry cache只保存最近造訪過的目錄項,如果要找的目錄項在cache中沒有,就要從磁碟讀到記憶體。
每個dentry
結構體都有一個指標指向inode
結構體。 inode
結構體保存著從磁碟inode讀上來的資訊。在上圖的例子中,有兩個dentry,分別表示/home/akaedu/a
和/home/akaedu/b
,它們都指向同一個inode,說明這兩個文件互為硬連結。 inode
結構體中保存著從磁碟分割區的inode讀取上來訊息,例如擁有者、檔案大小、檔案類型和權限位元等。每個inode
結構體都有一個指向inode_operations
結構體的指針,後者也是一組函數指針指向一些完成文件目錄操作的內核函數。和file_operations
不同,inode_operations
所指向的不是針對某一個檔案進行操作的函數,而是影響檔案和目錄佈局的函數,例如新增刪除檔案和目錄、追蹤符號鏈接等等,屬於同一檔案系統的各inode
結構體可以指向同一個inode_operations
結構體。
inode
結構體有一個指向super_block
結構體的指標。 super_block
結構體保存著從磁碟分割區的超級區塊讀取上來的信息,例如檔案系統類型、區塊大小等。 super_block
結構體的s_root
成員是指向dentry
的指針,表示這個檔案系統的根目錄被mount
到哪裡,在上圖的例子中這個分割區被mount
到/home
目錄下。
file
、dentry
、inode
、super_block
這幾個結構體組成了VFS(虛擬檔案系統VFS ,Virtual Filesystem)的核心概念。
1.3對檔案描述符的操作
(1).查看Linux檔案描述子
1 [root@localhost ~]# sysctl -a | grep -i file-max --color 3 fs.file-max = 392036 5 [root@localhost ~]# cat /proc/sys/fs/file-max 7 392036 9 [root@localhost ~]# ulimit -n11 102413 [root@localhost ~]#
Linux下最大檔案描述子的限制有兩個方面,一個是用戶級的限制,另外一個則是系統級限制。
系統級限制:sysctl命令和proc檔案系統中查看到的數值是一樣的,這屬於系統級限制,它是限制所有使用者開啟檔案描述符的總和
用戶級限制:ulimit指令看到的是用戶級的最大檔案描述符限制,也就是說每個用戶登入後執行的程式佔用檔案描述符的總數不能超過這個限制
(2).修改檔案描述子的值
1 [root@localhost ~]# ulimit-SHn 102402 [root@localhost ~]# ulimit -n3 102404 [root@localhost ~]#
以上的修改只對目前會話起作用,是臨時性的,如果需要永久修改,則要修改如下:
1 [root@localhost ~]# grep -vE'^$|^#' /etc/security/limits.conf2 * hard nofile 40963 [root@localhost ~]#
1 //默认配置文件中只有hard选项,soft 指的是当前系统生效的设置值,hard 表明系统中所能设定的最大值2 [root@localhost ~]# grep -vE'^$|^#' /etc/security/limits.conf3 * hard nofile 102404 * soft nofile 102405 [root@localhost ~]#6 // soft<=hard soft的限制不能比hard限制高
(3).修改系統限制
1 [root@localhost ~]# sysctl -wfs.file-max=4000002 fs.file-max = 4000003 [root@localhost ~]# echo350000 > /proc/sys/fs/file-max //重启后失效4 [root@localhost ~]# cat /proc/sys/fs/file-max5 3500006 [root@localhost ~]#
//以上是暫時修改檔案描述符
//永久修改把fs.file-max=400000加入/etc/sysctl.conf中,使用sysctl -p即可
1.4用程式檢視檔案描述子
下面的程序,打開/home/shenlan/hello.c文件,如果此目錄下沒有hello.c文件,程式自動創建,程式中傳回的文件描述符為3。因為進程啟動時,開啟了標準輸入(0)、標準輸出(1)和標準出錯處理(2)三個文件,fd預設從最小的未被使用的下標開始分配,因此傳回的檔案描述符為3。
1 #include<stdio.h> 2 #include<sys/types.h> 3 #include<sys/stat.h> 4 #include<fcntl.h> 5 #include<stdlib.h> 6 int main() 7 { 8 int fd; 9 if((fd = open("/home/shenlan/fd.c",O_CREAT|O_WRONLY|O_TRUNC,0611))<0){10 perror("openfile fd.c error!\n");11 exit(1);12 }13 else{14 printf("openfile fd.c success:%d\n",fd);15 }16 if(close(fd) < 0){17 perror("closefile fd.c error!\n");18 exit(1);19 }20 else21 printf("closefile fd.c success!\n");22 exit(0);23 }
执行结果:
1.5进程打开一个文件的具体流程
进程通过系统调用open( )来打开一个文件,实质上是获得一个文件描述符,以便进程通过文件描述符为连接对文件进行其他操作。进程打开文件时,会为该文件创建一个file对象,并把该file对象存入进程打开文件表中(文件描述符数组),进而确定了所打开文件的文件描述符。 open( )操作在内核里通过sys_open( )实现的,sys_open( )将创建文件的dentry、inode和file对象,并在file_struct结构体的进程打开文件表fd_array[NR_OPEN_DEFAULT]中寻找一个空闲表项,然后返回这个表项的下标(索引),即文件描述符。创建文件的file对象时,将file对象的f_op指向了所属文件系统的操作函数集file_operations,而该函数集又来自具体文件的i节点,于是虚拟文件系统就与实际文件系统的操作衔接起来了。
2.C标准库中的FILE结构和文件描述符
C语言中使用的是文件指针而不是文件描述符做为I/O的句柄."文件指针(file pointer)"指向进程用户区中的一个被称为FILE结构的数据结构。FILE结构包括一个缓冲区和一个文件描述符值.而文件描述符值是文件描述符表中的一个索引.从某种意义上说文件指针就是句柄的句柄。流(如: fopen)返回的是一个FILE结构指针, FILE结构是包含有文件描述符的,FILE结构函数可以看作是对fd直接操作的系统调用的封装, 它的优点是带有I/O缓存。
从文件描述符fd 到文件流 FILE* 的函数是
FILE* fdopen(int filedes,const char* mode);
早期的C标准库中,FILE在stdio.h中定义;Turbo C中,参见谭浩强的《C程序设计》,FILE结构体中包含成员fd,即文件描述符。亦可以在安装的Ubuntu系统的/usr/include/stdio.h中找到struct _IO_FILE结构体,这个结构体比较复杂,我们只关心需要的部分-文件描述符,但是在这个的结构体中,我们并没有发现与文件描述符相关的诸如fd成员变量。此时,类型为int的_fileno结构体成员引起了我们的注意,但是不能确定其为文件描述符。因此写个程序测试是最好的办法,可以用以下的代码测试:
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<sys/types.h> 4 #include<sys/stat.h> 5 #include<fcntl.h> 6 int main( ) 7 { 8 char buf[50] = {"ILOVE this game!"}; 9 FILE *myfile;10 11 myfile = fopen("2.txt","w+");12 if(!myfile){13 printf("error:openfile failed!\n");14 }15 printf("The openedfile's descriptor is %d\n",myfile->_fileno);16 if(write(myfile->_fileno,buf,50)< 0){17 perror("error:writefile failed!\n");18 exit(1);19 }else{20 printf("writefile successed!\n");21 }22 exit(0);23 }
程式中,使用fopen函數以讀寫開啟2.txt文件,如果不存在2.txt文件,則建立此文件。並將其傳回的FILE指標myfile。使用printf向標準終端印出myfile->_fileno的值,並將myfile->_fileno作為檔案描述子傳遞給write 系統調用,向開啟的檔案寫入緩衝區資料。然後使用cat指令查看2.txt的內容。執行的結果如圖所示。 _fileno的值為3,因為標準輸入、輸出、出錯為0、1、2。輸出結果如下:
因此,_fileno成員即為作業系統開啟檔案傳回的句柄(windows系統)或檔案描述子。深入學習可以閱讀人民郵電出版社《C標準庫》。當然也可以閱讀/glibc-2.9/manual/io.txti檔。在 Linux中,檔案的描述子分配是從小到大逐個查詢檔案描述子是否已經使用,然後再分配,也可以寫程式測試。
檔案描述子表也稱為檔案描述子數組,其中存放了一個進程所開啟的所有檔案。檔案描述符數組包含在進程開啟的檔案表files_struct結構中。 在/include/linux/fdtable.h中定義,為一個指向file類型的指標陣列---fd_array[NR_OPEN_DEFAULT],其中NR_OPEN_DEFAULT也在fdtable.h中定義,這是一個和具體的CPU體系結構有關的變量,#define NR_OPEN_DEFAULTBITS_PER_LONG#。
#FILE結構和檔案描述子、file結構之間的關係可以用下圖來表示:
#
#以上是檔案描述符與FILE概念介紹的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

開啟微信,在我中選擇設置,選擇通用後選擇儲存空間,在儲存空間選擇管理,選擇要恢復檔案的對話選擇感嘆號圖示。教學適用型號:iPhone13系統:iOS15.3版本:微信8.0.24解析1先開啟微信,在我的頁面中點選設定選項。 2接著在設定頁面中找到並點選通用選項。 3然後在通用頁面中點選儲存空間。 4接下來在儲存空間頁面中點選管理。 5最後選擇要恢復檔案的對話,點選右側的感嘆號圖示。補充:微信文件一般幾天過期1要是微信接收的文件並沒有點開過的情況下,那在七十二鐘頭之後微信系統會清除掉,要是己經查看了微信

在Windows系統中,照片應用程式是一個方便的方式來檢視和管理照片和影片。透過這個應用程序,用戶可以輕鬆存取他們的多媒體文件,而無需安裝額外的軟體。然而,有時用戶可能會碰到一些問題,例如在使用照片應用程式時遇到「無法開啟此文件,因為不支援該格式」的錯誤提示,或在嘗試開啟照片或影片時出現文件損壞的問題。這種情況可能會讓使用者感到困惑和不便,需要進行一些調查和修復來解決這些問題。當用戶嘗試在Photos應用程式上開啟照片或影片時,會看到以下錯誤。抱歉,照片無法開啟此文件,因為目前不支援該格式,或該文件

在本文中,我們將介紹如何解決在Windows系統中刪除檔案或資料夾時出現「準備刪除」提示的問題。這個提示意味著系統正在進行一些背景操作,例如檢查檔案權限、驗證檔案是否被其他程式佔用、計算要刪除項目的大小等。我們將為您提供一些解決方法,以確保您能夠順利刪除文件,而無需等待太長時間。為什麼Windows要花這麼長時間才能刪除檔案? Windows準備刪除檔案所需的時間受多種因素影響,包括檔案大小、儲存裝置速度和後台進程。長時間或被卡住的「正在準備刪除」提示可能暗示系統資源不足、磁碟錯誤或檔案系統問題。在

Tmp格式檔案是一種暫存檔案格式,通常由電腦系統或程式在執行過程中產生。這些文件的目的是儲存臨時數據,以幫助程式正常運行或提高效能。一旦程式執行完成或電腦重啟,這些tmp檔案往往就沒有了存在的必要性。所以,對於Tmp格式檔案來說,它們本質上是可以刪除的。而且,刪除這些tmp檔案能夠釋放硬碟空間,確保電腦的正常運作。但是,在刪除Tmp格式檔案之前,我們需

gho檔案是一種GhostImage影像文件,它通常用於將整個硬碟或分割區的資料備份成一個檔案。在一些特定的情況下,我們需要將這種gho檔案重新安裝回硬碟上,以還原硬碟或分割區到先前的狀態。下面將介紹gho檔案的安裝方法。首先,在安裝之前,我們需要準備以下工具和材料:實體的gho文件:確保你擁有一份完整的gho文件,它通常以.gho為後綴名,並且包含有備份

在電腦中刪除或解壓縮資料夾,時有時會彈出提示對話框“錯誤0x80004005:未指定錯誤”,如果遇到這中情況應該怎麼解決呢?提示錯誤碼0x80004005的原因其實很多,但大部分因為病毒導致,我們可以重新註冊dll來解決問題,下面,小編給大夥講解0x80004005錯誤代碼處理經驗。有使用者在使用電腦時出現錯誤代碼0X80004005的提示,0x80004005錯誤主要是由於電腦沒有正確註冊某些動態連結庫文件,或電腦與Internet之間存在不允許的HTTPS連接防火牆所引起。那麼如何

想了解更多關於開源的內容,請造訪:51CTO鴻蒙開發者社群https://ost.51cto.com運行環境DAYU200:4.0.10.16SDK:4.0.10.15IDE:4.0.600一、建立應用程式點擊File- >newFile->CreateProgect。選擇模版:【OpenHarmony】EmptyAbility:填寫項目名,shici,應用包名com.nut.shici,應用儲存位置XXX(不要有中文,特殊字符,空格)。 CompileSDK10,Model:Stage。 Device

檔案路徑是作業系統中用於識別和定位檔案或資料夾的字串。在檔案路徑中,常見的有兩種符號分隔路徑,即正斜線(/)和反斜線()。這兩個符號在不同的作業系統中有不同的使用方式和意義。正斜線(/)是Unix和Linux系統中常用的路徑分隔符號。在這些系統中,檔案路徑是以根目錄(/)為起始點,每個目錄之間使用正斜線進行分隔。例如,路徑/home/user/Docume
