搜尋
首頁運維linux運維檔案描述符與FILE概念介紹

檔案描述符與FILE概念介紹

Jun 21, 2017 pm 01:44 PM
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),後面我們會講到,dupfork 等系統呼叫會導致多個檔案描述子指向同一個file結構體,例如有fd1fd2都引用同一個 file結構體,那麼它的引用計數就是2,當close(fd1)時並不會釋放file結構體,而只是把引用計數減到1,如果再close(fd2),引用計數就會減少到0同時釋放file結構體,這才真的關閉了檔案。

每個file結構體都指向一個file_operations結構體,這個結構體的成員都是函數指針,指向實作各種檔案操作的核心函數。例如在使用者程式中read一個檔案描述符,read#透過系統呼叫進入內核,然後找到這個檔案描述符所指向的file結構體,找到file結構體所指向的file_operations結構體,呼叫它的read成員所指向的核心函數以完成使用者請求。在使用者程式中呼叫lseekreadwriteioctlopen等函數,最後都由核心呼叫file_operations的各成員所指向的核心函數完成使用者請求。 file_operations結構體中的release成員用來完成使用者程式的close請求,之所以叫release而不叫 close是因為它不一定真的關閉文件,而是減少引用計數,只有引用計數減到0才關閉文件。對於同一個檔案系統上開啟的常規檔案來說,readwrite等檔案操作的步驟和方法應該是一樣的,呼叫的函數應該是相同的,所以圖中的三個開啟檔案的file結構體指向同一個file_operations結構體。如果開啟一個字元設備文件,那麼它的readwrite操作肯定和常規文件不一樣,不是讀寫磁碟的資料塊而是讀寫硬體設備,所以file結構體應該指向不同的file_operations結構體,其中的各種檔案操作函數由該裝置的驅動程式實作。

每個file結構體都有一個指向dentry結構體的指針,「dentry」是directory entry(目錄項目)的縮寫。我們傳給openstat等函數的參數的是路徑,例如/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目錄下。

filedentryinodesuper_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

(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> 3 #include<sys> 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))</stdlib.h></fcntl.h></sys></sys></stdio.h>
#

执行结果:

1.5进程打开一个文件的具体流程    

进程通过系统调用open( )来打开一个文件,实质上是获得一个文件描述符,以便进程通过文件描述符为连接对文件进行其他操作。进程打开文件时,会为该文件创建一个file对象,并把该file对象存入进程打开文件表中(文件描述符数组),进而确定了所打开文件的文件描述符。        open( )操作在内核里通过sys_open( )实现的,sys_open( )将创建文件的dentryinodefile对象,并在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标准库中,FILEstdio.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> 4 #include<sys> 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)</fcntl.h></sys></sys></stdlib.h></stdio.h>

程式中,使用fopen函數以讀寫開啟2.txt文件,如果不存在2.txt文件,則建立此文件。並將其傳回的FILE指標myfile。使用printf向標準終端印出myfile->_fileno的值,並將myfile->_fileno作為檔案描述子傳遞給write 系統調用,向開啟的檔案寫入緩衝區資料。然後使用cat指令查看2.txt的內容。執行的結果如圖所示。 _fileno的值為3,因為標準輸入、輸出、出錯為012。輸出結果如下:
    因此,_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中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
Linux:進入和退出維護模式Linux:進入和退出維護模式May 02, 2025 am 12:01 AM

進入Linux維護模式的方法包括:1.編輯GRUB配置文件,添加"single"或"1"參數並更新GRUB配置;2.在GRUB菜單中編輯啟動參數,添加"single"或"1"。退出維護模式只需重啟系統。通過這些步驟,你可以在需要時快速進入維護模式,並安全地退出,確保系統的穩定性和安全性。

了解Linux:定義的核心組件了解Linux:定義的核心組件May 01, 2025 am 12:19 AM

Linux的核心組件包括內核、shell、文件系統、進程管理和內存管理。 1)內核管理系統資源,2)shell提供用戶交互界面,3)文件系統支持多種格式,4)進程管理通過fork等系統調用實現,5)內存管理使用虛擬內存技術。

Linux的構建塊:關鍵組件解釋了Linux的構建塊:關鍵組件解釋了Apr 30, 2025 am 12:26 AM

Linux系統的核心組成部分包括內核、文件系統和用戶空間。 1.內核管理硬件資源並提供基本服務。 2.文件系統負責數據存儲和組織。 3.用戶空間運行用戶程序和服務。

使用維護模式:故障排除和修復Linux使用維護模式:故障排除和修復LinuxApr 29, 2025 am 12:28 AM

維護模式是Linux系統中通過單用戶模式或救援模式進入的特殊運行級別,用於系統維護和修復。 1.進入維護模式使用命令“sudosystemctlisolaterescue.target”。 2.在維護模式中,可以檢查並修復文件系統,使用命令“fsck/dev/sda1”。 3.高級用法包括重置root用戶密碼,需掛載文件系統為讀寫模式並編輯密碼文件。

Linux維護模式:了解目的Linux維護模式:了解目的Apr 28, 2025 am 12:01 AM

維護模式用於系統維護和修復,允許管理員在簡化環境中工作。 1.系統修復:修復損壞的文件系統和啟動加載器。 2.密碼重置:重置root用戶密碼。 3.軟件包管理:安裝、更新或刪除軟件包。通過修改GRUB配置或使用特定鍵進入維護模式,執行維護任務後可安全退出。

Linux操作:網絡和網絡配置Linux操作:網絡和網絡配置Apr 27, 2025 am 12:09 AM

Linux網絡配置可以通過以下步驟完成:1.配置網絡接口,使用ip命令臨時設置或編輯配置文件持久化設置。 2.設置靜態IP,適合需要固定IP的設備。 3.管理防火牆,使用iptables或firewalld工具來控製網絡流量。

Linux中的維護模式:系統管理員指南Linux中的維護模式:系統管理員指南Apr 26, 2025 am 12:20 AM

維護模式在Linux系統管理中扮演關鍵角色,幫助進行系統修復、升級和配置變更。 1.進入維護模式可以通過GRUB菜單選擇或使用命令“sudosystemctlisolaterescue.target”。 2.在維護模式下,可以執行文件系統修復和系統更新等操作。 3.高級用法包括重置root密碼等任務。 4.常見錯誤如無法進入維護模式或掛載文件系統,可通過檢查GRUB配置和使用fsck命令修復。

Linux中的維護模式:何時以及為什麼使用它Linux中的維護模式:何時以及為什麼使用它Apr 25, 2025 am 12:15 AM

使用Linux維護模式的時機和原因:1)系統啟動問題時,2)進行重大系統更新或升級時,3)執行文件系統維護時。維護模式提供安全、控制的環境,確保操作的安全性和效率,減少對用戶的影響,並增強系統的安全性。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

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

熱工具

SecLists

SecLists

SecLists是最終安全測試人員的伙伴。它是一個包含各種類型清單的集合,這些清單在安全評估過程中經常使用,而且都在一個地方。 SecLists透過方便地提供安全測試人員可能需要的所有列表,幫助提高安全測試的效率和生產力。清單類型包括使用者名稱、密碼、URL、模糊測試有效載荷、敏感資料模式、Web shell等等。測試人員只需將此儲存庫拉到新的測試機上,他就可以存取所需的每種類型的清單。

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。