C庫函數

? ? ? ? Linux的系統I/O函數(read、write、open、close和 lseek等)與C語言的C庫函數(libc.so庫文件中)都是相對應的,它們都是動態庫函數。如下圖所示,C庫函數有fopen、fclose、fwrite、fread和fseek等。這些C庫函數都封裝在libc.so庫文件中,其中的fopen函數用于打開一個文件,其返回值為FILE *類型(指向FILE類型的一個指針),FILE類型為一個結構體,用于描述對打開的文件的一些操作,對于除了fopen以外的C庫函數都會通過這個FILE *類型指針對打開的文件進行操作。

FILE類型為一個結構體,包括三個部分:文件描述符、文件讀寫指針和I/O緩沖區。

文件描述符(整型)用于索引到對應的磁盤文件,類似于FCB(文件控制塊)和索引結點,包含了該文件在磁盤上的位置信息。對于每一個進程打開的所有文件在其PCB中都有記錄相應的文件描述符,如0代表標準輸入,其宏定義為STDIN_FILENO(#define STDIN_FILENO 0)。所有執行I/O操作的系統調用都以文件描述符,即一個非負整數來指代所打開的文件。文件描述符可以用來表示所有類型的已打開文件。同時,多個文件描述符可以指向同一個打開文件,因為有在不同進程中打開同一個文件的需求。

文件描述符是一個整型數,文件描述符表是一個整型數組,而在PCB中有一個指針,指向文件描述符表的首地址,因此根據PCB就可以找到對應的文件描述符,而每一個文件描述符都對應一個FILE *的指針,即可以根據文件描述符進一步找到FILE結構體,該結構體保存了所打開文件的屬性信息(文件大小、I/O緩沖、讀寫指針、文件打開次數等等),而這樣的結構體每個文件都只有一份,供所有打開該文件的進程共享,而這些進程所不同的只是文件描述符不一樣。FILE結構體的內容只有一份。FILE結構體類似inode,而文件描述符類似簡化的FCB。

每一個文件只有一個文件讀寫指針(讀寫文件過程中指針的實際位置),在文件讀寫時要時刻注意當前文件指針的位置。文件讀寫指針指向將要寫入或讀出的下一個地址。如果一個進程對文件正在進行寫入,此時另一個進程要讀取該文件的數據,需要利用fseek函數將文件讀寫指針置于文件的起始位置才能讀取數據。

系統調用指操作系統提供給用戶程序調用的一組接口(接口函數)來獲得內核提供的服務。在實際中程序員使用的通常不是系統調用,而應用程序接口API,也稱為系統調用編程接口,接口函數可能要一個或者幾個系統調用才能完成函數功能,此函數通過c庫(libc)實現,如fread,fopen等。

I/O緩沖區。每一個C庫函數在對文件操作時都會有對應的I/O緩沖區,I/O緩沖區屬于內存的一部分,位于用戶空間,默認大小為8KB,即8192個Bytes。

以fgetc / fputc函數為例,當用戶程序第一次調用fgetc 讀一個字節時,fgetc函數可能通過系統調用進入內核讀1K字節到I/O緩沖區中,然后返回I/O緩沖區中的第一個字節給用戶,把讀寫位置指向I/O緩沖區中的第二個字符,以后用戶再調fgetc ,就直接從I/O緩沖區中讀取,而不需要進內核了,當用戶把這1K字節都讀完之后,再次調用fgetc時,fgetc 函數會再次進入內核讀1K字節到I/O緩沖區中。C標準庫之所以會從內核預讀一些數據放 在I/O緩沖區中,是希望用戶程序隨后要用到這些數據,C標準庫的I/O緩沖區也在用戶空間,直接從用戶空間讀取數據比進內核讀數據要快得多。另一方面,用戶程序調用fputc通常只是寫到I/O緩沖區中,這樣fputc 函數可以很快地返回,如果I/O緩沖區寫滿了,fputc 就通過系統調用把I/O緩沖區中的數據傳給內核,內核最終把數據寫回磁盤或設備。有時候用戶程序希望把I/O緩沖區中的數據立刻給內核,讓內核寫回設備或磁盤,這稱為Flush操作,對應的庫函數是fflush,fclose函數在關閉文件之前也會做Flush操作。

由上可以看出,fgetc和fputc庫函數在完成工作的過程中可能需要幾個系統調用,如將I/O緩沖區的數據寫入內核緩沖,將內核緩沖數據刷到磁盤上等。因此,通過增設I/O緩沖區和內核緩沖可以減少進入內核的次數和對磁盤的操作次數(這些都需要系統調用來完成),從而提高了讀寫效率。相對于內存,機械硬盤的讀寫速度很慢。機械硬盤的讀寫尋道時間ms級,而內存的讀寫速度是ns級別。另外,從用戶空間(I/O緩沖區)直接讀寫數據也會比進入內核(系統調用)要快很多。

Flush操作。指把I/O緩沖區的數據立即傳送給內核,然后刷到磁盤上,分為強制性和非強制性兩種。C庫函數fflush是強制性把I/O緩沖區的數據立即寫給內核的緩沖區;C庫函數fsync是強制性把內核緩沖區的數據立即刷到磁盤上。main函數的return和調用main函數中的exit(退出當前進程),也會把緩沖區的數據立即寫到磁盤上。I/O緩沖區已經寫滿或者關閉文件時,將會自動將其數據寫到磁盤上。

內核緩沖區。人生三大錯覺之中的一個:在調用函數write()時,我們覺得該函數一旦返回,數據便已經寫到了文件里,可是這樣的概念僅僅是宏觀上的。實際上,操作系統實現某些文件I/O時(如磁盤文件),為了保證I/O的效率,在內核一般會用到一片專門的區域(內存或獨立的I/O地址空間)作為I/O數據緩沖區.它用在輸入輸出設備和CPU之間,用來緩存數據,使得低速的設備和快速的CPU可以協調工作避免低速的輸入輸出設備長時間占用CPU,降低系統調用,提高了CPU的工作效率。

Linux系統I/O函數是沒有I/O緩沖區的,其緩存是由用戶提供的。C庫函數都有對應的I/O緩沖區8KB(8196Bytes)。注意:內核緩沖和I/O緩沖的作用不同

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/385413.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/385413.shtml
英文地址,請注明出處:http://en.pswp.cn/news/385413.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【Leetcode | 48】226. 翻轉二叉樹

翻轉一棵二叉樹。 示例: 輸入: 4 / \ 2 7 / \ / \ 1 3 6 9 輸出: 4 / \ 7 2 / \ / \ 9 6 3 1 備注: 這個問題是受到 Max Howell 的 原問題 啟發的 : 谷歌:我們90%的…

C庫函數與Linux系統函數之間的關系

由上小節知道,C庫函數是借助FILE類型的結構體來對文件進行操作的,其本身只是在用戶空間(I/O緩沖區)進行讀寫操作,而數據在內核與用戶空間之間的傳遞、以及將內核與I/O設備之間的數據傳遞都是該C庫函數進行一系列的系統…

【第十六章】模板實參推斷

二、模板顯式推斷 在C中&#xff0c;若函數模板返回類型需要用戶指定&#xff0c;那么在定義函數模板時&#xff0c;模板參數的順序是很重要的&#xff0c;如下代碼&#xff1a; template <typename T1, typename T2, typename T3> //模板一 T1 sum(T2 a, T3 b) {retu…

open函數和errno全局變量

&#xff08;1&#xff09;open函數 man man 查看man文檔的首頁 其中DESCRIPTION部分描述了man文檔的每一章的章節內容 第2章System calls為系統調用&#xff0c;即Liunx系統函數。 man 2 open 查看第二章的open函數的詳細幫助文件。 open函數用于打開一個已經的文件或者創…

open函數和close函數的使用

學習幾個常用的Linux系統I/O函數&#xff1a;open、close、write、read和lseek。注意&#xff0c;系統調用函數必須都考慮返回值。 &#xff08;1&#xff09;open函數的使用 首先&#xff0c;需要包含三個頭文件&#xff1a;<sys/types.h> <sys/stat.h> <…

【Leetcode | 9】217. 存在重復元素

解題代碼&#xff1a; bool containsDuplicate(vector<int>& nums) {return nums.size() > set<int>(nums.begin(), nums.end()).size(); }

全緩沖、行緩沖和無緩沖

這里的緩沖是指的是用戶空間的I/O緩沖區&#xff0c;不是內核緩沖。 無緩沖&#xff1a;用戶層不提供緩沖&#xff0c;數據流直接到內核緩沖&#xff0c;再到磁盤等外設上。標準錯誤輸出&#xff08;2&#xff09;通常是無緩存的&#xff0c;因為它必須盡快輸出&#xff0c;且…

【Leetcode】1. 兩數之和

給定一個整數數組 nums 和一個目標值 target&#xff0c;請你在該數組中找出和為目標值的那 兩個 整數&#xff0c;并返回他們的數組下標。 你可以假設每種輸入只會對應一個答案。但是&#xff0c;你不能重復利用這個數組中同樣的元素。 示例: 給定 nums [2, 7, 11, 15], targ…

read和write函數的使用

都需要包含頭文件&#xff1a; <unistd.h> read系統函數從打開的設備或文件中讀取數據&#xff0c;即將數據從外設上經過內核讀到用戶空間&#xff1b;write系統函數相反&#xff0c;向打開的設備或文件中寫入數據&#xff0c;即將數據從用戶空間&#xff08;I/O緩沖&am…

1091. Acute Stroke (30)

One important factor to identify acute stroke (急性腦卒中) is the volume of the stroke core. Given the results of image analysis in which the core regions are identified in each MRI slice, your job is to calculate the volume of the stroke core. Input Speci…

lseek函數的使用

需要包含頭文件&#xff1a;<sys/types.h> <unistd.h> off_t lseek(int fd, off_t offset, int whence)&#xff1b; 函數原型 函數功能&#xff1a;移動文件讀寫指針&#xff1b;獲取文件長度&#xff1b;拓展文件空間。 在使用該函數之前需要將文件打開&…

19. 刪除鏈表的倒數第N個節點

給定一個鏈表&#xff0c;刪除鏈表的倒數第 n 個節點&#xff0c;并且返回鏈表的頭結點。 示例&#xff1a; 給定一個鏈表: 1->2->3->4->5, 和 n 2. 當刪除了倒數第二個節點后&#xff0c;鏈表變為 1->2->3->5. 說明&#xff1a; 給定的 n 保證是有效的。…

文件操作相關的系統函數

重點學習&#xff1a;stat&#xff08;fstat、lstat 獲取文件屬性&#xff09;、access&#xff08;測試指定文件是否擁有某種權限&#xff09;、chmod&#xff08;改變文件的權限&#xff09;、chown&#xff08;改變文件的所屬主和所屬組&#xff09;、truncate&#xff08;截…

stat函數(stat、fstat、lstat)

#include <sys/types.h> #include <sys/stat.h> #include <unistd.h> //需包含頭文件 有如下三個函數的函數原型&#xff1a; int stat(const char *path, struct stat *buf); 第一個形參&#xff1a;指出文件&#xff08;文件路徑&#xff09;&…

1062. Talent and Virtue (25)

About 900 years ago, a Chinese philosopher Sima Guang wrote a history book in which he talked about peoples talent and virtue. According to his theory, a man being outstanding in both talent and virtue must be a "sage&#xff08;圣人&#xff09;"…

access、strtol函數的使用(后者為C庫函數)

#include <unistd.h> int access(const char *pathname, int mode); 作用&#xff1a;檢查調用該函數的進程是否可以對指定的文件執行某種操作。 第一個形參&#xff1a;文件名&#xff1b;第二個形參&#xff1a;R_OK&#xff08;是否可讀&#xff09;、W_OK&#xf…

chmod、chown函數的使用

#include <sys/stat.h> int chmod(const char *path, mode_t mode); int fchmod(int fd, mode_t mode); 作用&#xff1a;改變指定文件的權限。第二個參數&#xff1a;mode必須為一個8進制數&#xff1b;返回值為0表示成功&#xff0c;-1表示失敗。 //代碼 #include…

606. 根據二叉樹創建字符串

你需要采用前序遍歷的方式&#xff0c;將一個二叉樹轉換成一個由括號和整數組成的字符串。 空節點則用一對空括號 "()" 表示。而且你需要省略所有不影響字符串與原始二叉樹之間的一對一映射關系的空括號對。 示例 1: 輸入: 二叉樹: [1,2,3,4] 1 / \ …

truncate、rename函數的使用

#include <unistd.h> #include <sys/types.h> int truncate(const char *path, off_t length); int ftruncate(int fd, off_t length); 作用&#xff1a;用于拓展或截斷文件。將參數path 指定的文件大小改為參數length 指定的大小。如果原來的文件大小比參數le…

【Leetcode】112. 路徑總和

給定一個二叉樹和一個目標和&#xff0c;判斷該樹中是否存在根節點到葉子節點的路徑&#xff0c;這條路徑上所有節點值相加等于目標和。 說明: 葉子節點是指沒有子節點的節點。 示例: 給定如下二叉樹&#xff0c;以及目標和 sum 22&#xff0c; 5 / \ …