linux下對檔案操作有兩種方式:系統呼叫(system call)和庫函式呼叫(library functions)。可以參考《linux程式設計》(英文原版為《beginning linux programming》,作者是neil matthew和richard stones)第三章: working with files。系統呼叫實際上就是指最底層的乙個呼叫,在linux程式設計裡面就是底層呼叫的意思。面向的是硬體。而庫函式呼叫則面向的是應用開發的,相當於應用程式的api,採用這樣的方式有很多種原因,第一:雙緩衝技術的實現。第二,可移植性。第三,底層呼叫本身的一些效能方面的缺陷。第四:讓api也可以有了級別和專門的工作面向。
一、系統呼叫
顧名思意,系統呼叫說的是作業系統提供給使用者程式呼叫的一組「特殊」介面。使用者程式可以通過這組「特殊」介面來獲得作業系統核心提供的服務,比如使用者可以通過檔案系統相關的呼叫請求系統開啟檔案、關閉檔案或讀寫檔案,可以通過時鐘相關的系統呼叫獲得系統時間或設定系統時間等。
從邏輯上來說,系統呼叫可被看成是乙個核心與使用者空間程式互動的介面——它好比乙個中間人,把使用者程序的請求傳達給核心,待核心把請求處理完畢後再將處理結果送回給使用者空間。
系統服務之所以需要通過系統呼叫提供給使用者空間的根本原因是為了對系統「保護」,因為我們知道linux的執行空間分為核心空間與使用者空間,它們各自執行在不同的級別中,邏輯上相互隔離。所以使用者程序在通常情況下不允許訪問核心資料,也無法使用核心函式,它們只能在使用者空間操作使用者資料,調使用者用空間函式。比如我們熟悉的「helloworld」程式(執行時)就是標準的使用者空間程序,它使用的列印函式printf就屬於使用者空間函式,列印的字元「helloworld」字串也屬於使用者空間資料。
系統呼叫提供的函式如open, close, read, write, ioctl等,需包含標頭檔案unistd.h。以write為例:其函式原型為 size_t write(int fd, const void *buf, size_t nbytes),其操作物件為檔案描述符或檔案控制代碼fd(file descriptor),要想寫乙個檔案,必須先以可寫許可權用open系統呼叫開啟乙個檔案,獲得所開啟檔案的fd,例如 fd=open(\"/dev/video\", o_rdwr)。fd是乙個整型值,每新開啟乙個檔案,所獲得的fd為當前最大fd加1。linux系統預設分配了3個檔案描述符值:0-standard input,1-standard output,2-standard error。
系統呼叫通常用於底層檔案訪問(low-level file access),例如在驅動程式中對裝置檔案的直接訪問。
系統呼叫是作業系統相關的,因此一般沒有跨作業系統的可移植性。
系統呼叫發生在核心空間,因此如果在使用者空間的一般應用程式中使用系統呼叫來進行檔案操作,會有使用者空間到核心空間切換的開銷。事實上,即使在使用者空間使用庫函式來對檔案進行操作,因為檔案總是存在於儲存介質上,因此不管是讀寫操作,都是對硬體(儲存器)的操作,都必然會引起系統呼叫。也就是說,庫函式對檔案的操作實際上是通過系統呼叫來實現的。例如c庫函式fwrite()就是通過write()系統呼叫來實現的。
這樣的話,使用庫函式也有系統呼叫的開銷,為什麼不直接使用系統呼叫呢?這是因為,讀寫檔案通常是大量的資料(這種大量是相對於底層驅動的系統呼叫所實現的資料操作單位而言),這時,使用庫函式就可以大大減少系統呼叫的次數。這一結果又緣於緩衝區技術。在使用者空間和核心空間,對檔案操作都使用了緩衝區,例如用fwrite寫檔案,都是先將內容寫到使用者空間緩衝區,當使用者空間緩衝區滿或者寫操作結束時,才將使用者緩衝區的內容寫到核心緩衝區,同樣的道理,當核心緩衝區滿或寫結束時才將核心緩衝區內容寫到檔案對應的硬體媒介。
二、庫函式呼叫
標準c庫函式提供的檔案操作函式如fopen, fread, fwrite, fclose, fflush, fseek等,需包含標頭檔案stdio.h。以fwrite為例,其函式原型為size_t fwrite(const void *buffer, size_t size, size_t item_num, file *pf),其操作物件為檔案指標file *pf,要想寫乙個檔案,必須先以可寫許可權用fopen函式開啟乙個檔案,獲得所開啟檔案的file結構指標pf,例如pf=fopen(\"~/proj/filename\", \"w\")。實際上,由於庫函式對檔案的操作最終是通過系統呼叫實現的,因此,每開啟乙個檔案所獲得的file結構指標都有乙個核心空間的檔案描述符fd與之對應。同樣有相應的預定義的file指標:stdin-standard input,stdout-standard output,stderr-standard error。
庫函式呼叫通常用於應用程式中對一般檔案的訪問。
庫函式呼叫是系統無關的,因此可移植性好。
由於庫函式呼叫是基於c庫的,因此也就不可能用於核心空間的驅動程式中對裝置的操作。
三、系統呼叫、使用者程式設計介面(api)、系統命令、和核心函式的關係
系統呼叫並非直接和程式設計師或系統管理員打交道,它僅僅是乙個通過軟中斷機制(我們後面講述)向核心提交請求,獲取核心服務的介面。而在實際使用中程式設計師呼叫的多是使用者程式設計介面——api,而管理員使用的則多是系統命令。
使用者程式設計介面其實是乙個函式定義,說明了如何獲得乙個給定的服務,比如read()、malloc()、free()、abs()等。它有可能和系統呼叫形式上一致,比如read()介面就和read系統呼叫對應,但這種對應並非一一對應,往往會出現幾種不同的api內部用到統一個系統呼叫,比如malloc()、free()內部利用brk( )系統呼叫來擴大或縮小程序的堆;或乙個api利用了好幾個系統呼叫組合完成服務。更有些api甚至不需要任何系統呼叫——因為它不必需要核心服務,如計算整數絕對值的abs()介面。
四、函式庫呼叫 vs 系統呼叫
系統呼叫:它是核心態開放給使用者態的介面,以軟中斷實現。
函式呼叫:它是使用者態層面的概念,與核心態無關。
Linux系統呼叫和庫函式呼叫
linux下對檔案操作有兩種方式 系統呼叫 system call 和庫函式呼叫 library functions 可以參考 linux程式設計 英文原版為 beginning linux programming 作者是neil matthew和richard stones 第三章 working...
linux系統呼叫和庫函式呼叫
linux下對檔案操作有兩種方式 系統呼叫 system call 和庫函式呼叫 library functions 可以參考 linux程式設計 英文原版為 beginning linux programming 作者是neil matthew和richard stones 第三章 working...
linux系統呼叫和庫函式呼叫的區別
linux下對檔案操作有兩種方式 系統呼叫 system call 和庫函式呼叫 library functions 可以參考 linux程式設計 英文原版為 beginning linux programming 作者是neil matthew和richard stones 第三章 working...