Linux File I/O — 系統核心溝通的起點

更新 發佈閱讀 9 分鐘

這次講到的部分, 目前在Linux Foundation OpenBMC當中比較少會用到或需要去更改,但如果有需要寫Bridge IC相關的,OpenBIC的code,就會比較有感覺。其實早期Meta OpenBMC也很常需要寫File IO相關的code在Application,像是Firmware update/ Sensor Monitoring ...etc都是要讀取檔案, 或是透過Open Device Path去處理。那我們就再一起來複習一下使用者空間 (Userspace) 與 核心空間 (Kernel Space) 邊界設計哲學。

File Descriptor

想像你的程式 (Process) 走進一家餐廳 (Linux Kernel)。核心會為每個行程維護一份專屬的檔案清單 (File Table) 。當你的程式開啟一個檔案,核心就會從這個清單中取出一個未使用的整數作為該檔案的 FD,並回傳給你。FD 就是你用來索引和參考這個檔案的號碼牌 。預設的三大標準 FD:

  • FD 0:標準輸入 (stdin)
    • 這是歷史慣例所訂定的檔案描述子0
  • FD 1:標準輸出 (stdout)
    • 檔案描述子1,通常對應到你的終端機顯示器
    • 你在 C 程式中使用printf() 的輸出,預設就是送往 FD 1 。
  • FD 2:標準錯誤 (stderr)
    • 檔案描述子2,它也通常導向到你的終端機顯示器
    • 它的作用是允許你將程式中的錯誤訊息與正常的程式輸出分流處理,方便你單獨捕捉錯誤 。

System Call vs Buffered I/O

在 C 語言中,我們常看到兩組看似相似、但其實層級不同的檔案操作函式:

1. Buffered I/O(緩衝式輸入輸出)
使用帶有 f 前綴 的函式,例如:

fopen(), fread(), fwrite(), fclose()

這些函式屬於 C 標準函式庫(C Standard Library),主要運作在 使用者空間(Userspace)。它們會回傳一個 File Pointer (FILE *),並且定義於 man page 的 Section 3。可以把它想成是系統呼叫(system call)的「包裝(wrapper)」:在底層仍然會呼叫 open()read()write(),但額外在使用者空間建立了一層 buffer(緩衝區) 來加速存取。

2. System Call(系統呼叫)
使用 不帶 f 前綴 的函式,例如:

open(), read(), write(), close()

這些函式是直接與 Linux Kernel 互動的介面。它們會回傳一個整數型別的 File Descriptor (FD),用來唯一識別該進程所開啟的檔案。這些函式定義於 man page 的 Section 2

緩衝區機制(Buffering Mechanism)
當你使用 fread() 讀取資料時,即使只要求讀取一個位元組,它可能會一次透過系統呼叫從核心讀入一整塊資料(例如 4KB),並暫存在使用者空間的緩衝區中。 之後若程式再要求更多資料,就能直接從緩衝區讀取,而不需要再進行額外的 system call。這樣做的目的,是為了 減少使用者空間與核心空間之間的切換(context switch)次數,提升 I/O 效能。

開啟與建立檔案 (open)

在 Linux 系統程式設計中,open() 是一切檔案操作的開端。
它的作用是:將一個檔案路徑(pathname)與一個 File Descriptor(檔案描述子, FD)建立連結。

int fd = open("file.txt", O_RDWR | O_CREAT, 0644);

這個函式呼叫可以拆解成兩個關鍵部分:

  • Flags(開啟模式)
    flags 參數用來決定你要以何種方式開啟檔案。可以使用 bitwise OR (|) 運算符組合多個模式:
    • O_RDONLY:Read only(唯讀)
    • O_WRONLY:Write only(唯寫)
    • O_RDWR:Read and write(可讀可寫)
    • O_CREAT:若檔案不存在則建立新檔
    • O_APPEND:每次寫入都從檔尾追加
    • O_SYNC:啟用同步 I/O:寫入動作必須等到資料實際寫入磁碟後才算成功
為什麼 O_SYNC 重要?
一般情況下,write() 完成時資料可能還停留在核心緩衝區,若系統異常關機,資料可能尚未寫入磁碟。 使用 O_SYNC 可強制所有寫入同步到實體儲存裝置,確保資料一致性(但會犧牲部分效能)。
  • Mode(權限設定)
    當使用 O_CREAT 建立新檔案時,必須同時指定 mode 參數來設定檔案的權限。這個參數以八進位(octal)形式表示檔案的存取權限,對應 Linux 的三組使用者分類: 使用者 (User)群組 (Group)、以及其他人 (Other)
    每組權限由三個位元組成,分別代表「讀 (r)」、「寫 (w)」、「執行 (x)」。數值上,讀是 4,寫是 2,執行是 1,三者加總後形成該組的權限。
    例如 0644 代表:
    • 使用者(owner)擁有讀寫權限(6 = 4 + 2),
    • 群組與其他人則僅有讀取權限(4)。

strace:看見使用者與核心的對話

在學習 Linux File I/O 時,最能讓人真正體會「使用者空間(User Space)」與「核心空間(Kernel Space)」之間互動細節的工具,就是 strace。可以把 strace 想像成一個專門為 Linux 系統呼叫(System Calls)設計的 Protocol Analyzer

它能即時顯示出你的程式在執行期間,究竟對核心發出了哪些系統呼叫、傳入了哪些參數、又收到了什麼回傳值。 這意味著你不需要修改任何程式碼,就能直接觀察整個使用者空間與核心空間之間的「對話紀錄」。舉個例子,假設你執行一個讀取空檔案的簡單程式,strace 可能會輸出以下內容:

open("empty_file", O_RDWR|O_CREAT, 0666) = 3
read(3, "", 1024) = 0

從這兩行輸出,我們可以完整看到系統互動的過程:
首先,程式呼叫 open() 來開啟檔案,核心成功建立連線並回傳一個 File Descriptor(這裡是 3)。
接著,程式對這個 FD 3 執行 read() 操作,核心則回傳 0,代表這個檔案沒有內容可讀,也就是已經到達檔案結尾(EOF)。

這種觀察方式非常直觀,因為它讓你能夠從「系統層級」理解程式在做什麼。

更厲害的是,strace 並不需要程式的原始碼——即使只有一個已編譯完成的二進位執行檔(binary executable),也能被 strace 監看。大家可以試試看,假設你有一個簡單的 C 程式,只做一件事:開啟一個檔案並嘗試讀取內容。

#include <fcntl.h>
#include <unistd.h>

int main() {
int fd = open("empty.txt", O_RDWR | O_CREAT, 0666);
char buf[100];
read(fd, buf, sizeof(buf));
close(fd);
return 0;
}

你將這段程式編譯並執行:

gcc readfile.c -o readfile
./readfile

表面上,程式什麼都沒輸出;但如果我們在前面加上 strace,你就能看到它與核心之間的一場「對話」:

strace ./readfile

你可以看一下你的終端機會出現怎樣的輸出?
這篇就先到這裡,大家趕快動手試試看呦!

留言
avatar-img
L'Angolo di Embedded
25會員
26內容數
這裡會有一些我對於OpenBMC, Embedded Software的學習與經驗分享, 本來只在Line社群跟大家互動, 但是有夥伴提出想要看到歷史文章的需求, 於是我決定把它放到這裡, 努力磨練自己的技術和文筆。
L'Angolo di Embedded 的其他內容
2025/09/29
本文旨在深入剖析 Linux 檔案系統的核心概念,包括「萬物皆檔案」的哲學、檔案路徑、存取機制、inode 運作原理、連結機制、特殊檔案以及 OpenBMC 特有的檔案系統架構。透過理解這些基礎知識,開發者能更有效地在嵌入式系統中與硬體互動,並掌握 OpenBMC 的檔案系統設計。
2025/09/29
本文旨在深入剖析 Linux 檔案系統的核心概念,包括「萬物皆檔案」的哲學、檔案路徑、存取機制、inode 運作原理、連結機制、特殊檔案以及 OpenBMC 特有的檔案系統架構。透過理解這些基礎知識,開發者能更有效地在嵌入式系統中與硬體互動,並掌握 OpenBMC 的檔案系統設計。
2025/09/22
一起探討嵌入式系統開發中至關重要的建置系統與GNU工具鏈,涵蓋預處理、編譯、組譯、連結、定位與載入等步驟,並比較原生編譯與交叉編譯,最後介紹Make和Meson建置系統,以及提升嵌入式程式碼開發效率的技巧。
2025/09/22
一起探討嵌入式系統開發中至關重要的建置系統與GNU工具鏈,涵蓋預處理、編譯、組譯、連結、定位與載入等步驟,並比較原生編譯與交叉編譯,最後介紹Make和Meson建置系統,以及提升嵌入式程式碼開發效率的技巧。
2025/09/16
D-Bus基本工具busctl、dbus-monitor、dbus-send的使用方法與實例,並涵蓋Method、Property、Signal、Interface、D-Bus Signature等核心概念及進階容器型別應用,搭配實作範例與練習,助你輕鬆掌握D-Bus程式間通訊技巧。
Thumbnail
2025/09/16
D-Bus基本工具busctl、dbus-monitor、dbus-send的使用方法與實例,並涵蓋Method、Property、Signal、Interface、D-Bus Signature等核心概念及進階容器型別應用,搭配實作範例與練習,助你輕鬆掌握D-Bus程式間通訊技巧。
Thumbnail
看更多
你可能也想看
Thumbnail
背景:從冷門配角到市場主線,算力與電力被重新定價   小P從2008進入股市,每一個時期的投資亮點都不同,記得2009蘋果手機剛上市,當時蘋果只要在媒體上提到哪一間供應鏈,隔天股價就有驚人的表現,當時光學鏡頭非常熱門,因為手機第一次搭上鏡頭可以拍照,也造就傳統相機廠的殞落,如今手機已經全面普及,題
Thumbnail
背景:從冷門配角到市場主線,算力與電力被重新定價   小P從2008進入股市,每一個時期的投資亮點都不同,記得2009蘋果手機剛上市,當時蘋果只要在媒體上提到哪一間供應鏈,隔天股價就有驚人的表現,當時光學鏡頭非常熱門,因為手機第一次搭上鏡頭可以拍照,也造就傳統相機廠的殞落,如今手機已經全面普及,題
Thumbnail
玩完PVE到搭個NAS,今次用OpenMediaVault。 又係Debian base,太懶,係咁禁Next,一大隻Partition過,結果中晒伏。 Storage/File Systems 搵唔到 / 個file system,Google左輪,搵唔到。試下搞下fstab,除左會開
Thumbnail
玩完PVE到搭個NAS,今次用OpenMediaVault。 又係Debian base,太懶,係咁禁Next,一大隻Partition過,結果中晒伏。 Storage/File Systems 搵唔到 / 個file system,Google左輪,搵唔到。試下搞下fstab,除左會開
Thumbnail
本文分析導演巴里・柯斯基(Barrie Kosky)如何運用極簡的舞臺配置,將布萊希特(Bertolt Brecht)的「疏離效果」轉化為視覺奇觀與黑色幽默,探討《三便士歌劇》在當代劇場中的新詮釋,並藉由舞臺、燈光、服裝、音樂等多方面,分析該作如何在保留批判核心的同時,觸及觀眾的觀看位置與人性幽微。
Thumbnail
本文分析導演巴里・柯斯基(Barrie Kosky)如何運用極簡的舞臺配置,將布萊希特(Bertolt Brecht)的「疏離效果」轉化為視覺奇觀與黑色幽默,探討《三便士歌劇》在當代劇場中的新詮釋,並藉由舞臺、燈光、服裝、音樂等多方面,分析該作如何在保留批判核心的同時,觸及觀眾的觀看位置與人性幽微。
Thumbnail
※ OPP第一大核心-封裝 封裝的精神在於將「方法」、「屬性」和「邏輯」包裝在類別裡面,透過類別的實例來實現。這樣外部物件不需要了解內部的實現細節,只需要知道如何使用該類別提供的接口即可。換句話說,封裝是將內部細節隱藏起來,只暴露必要的部分給使用者。 封裝的核心概念是,使用者如果想要接觸資料,只
Thumbnail
※ OPP第一大核心-封裝 封裝的精神在於將「方法」、「屬性」和「邏輯」包裝在類別裡面,透過類別的實例來實現。這樣外部物件不需要了解內部的實現細節,只需要知道如何使用該類別提供的接口即可。換句話說,封裝是將內部細節隱藏起來,只暴露必要的部分給使用者。 封裝的核心概念是,使用者如果想要接觸資料,只
Thumbnail
《轉轉生》(Re:INCARNATION)為奈及利亞編舞家庫德斯.奧尼奎庫與 Q 舞團創作的當代舞蹈作品,結合拉各斯街頭節奏、Afrobeat/Afrobeats、以及約魯巴宇宙觀的非線性時間,建構出關於輪迴的「誕生—死亡—重生」儀式結構。本文將從約魯巴哲學概念出發,解析其去殖民的身體政治。
Thumbnail
《轉轉生》(Re:INCARNATION)為奈及利亞編舞家庫德斯.奧尼奎庫與 Q 舞團創作的當代舞蹈作品,結合拉各斯街頭節奏、Afrobeat/Afrobeats、以及約魯巴宇宙觀的非線性時間,建構出關於輪迴的「誕生—死亡—重生」儀式結構。本文將從約魯巴哲學概念出發,解析其去殖民的身體政治。
Thumbnail
<iostream> ​在之前的文章有提到過,<iostream> 是專門處理程式的輸入 (input) 以及輸出 (output) 的函式庫。輸入輸出的對象是以電腦作為主角: 輸入指的是「把資料給電腦」,輸出指的是「從電腦那邊取得資料」。 在這個系列的文章中,程式輸入指的都是從鍵盤輸入資料給電
Thumbnail
<iostream> ​在之前的文章有提到過,<iostream> 是專門處理程式的輸入 (input) 以及輸出 (output) 的函式庫。輸入輸出的對象是以電腦作為主角: 輸入指的是「把資料給電腦」,輸出指的是「從電腦那邊取得資料」。 在這個系列的文章中,程式輸入指的都是從鍵盤輸入資料給電
Thumbnail
Lua 開檔寫檔的運用 io.output()...
Thumbnail
Lua 開檔寫檔的運用 io.output()...
Thumbnail
題目敘述 題目會給我們一組定義好的界面和需求,要求我們設計一個資料結構,可以滿足平均O(1)的插入元素、刪除元素、隨機取得元素的操作。 RandomizedSet() 類別建構子 bool insert(int val) 插入元素的function界面 bool remove(int val
Thumbnail
題目敘述 題目會給我們一組定義好的界面和需求,要求我們設計一個資料結構,可以滿足平均O(1)的插入元素、刪除元素、隨機取得元素的操作。 RandomizedSet() 類別建構子 bool insert(int val) 插入元素的function界面 bool remove(int val
Thumbnail
軟體系統的發展歷程大多相似,首重解決基本需求、提供操作介面,進而提升安全性、擴充功能、優化操作。
Thumbnail
軟體系統的發展歷程大多相似,首重解決基本需求、提供操作介面,進而提升安全性、擴充功能、優化操作。
Thumbnail
這是一場修復文化與重建精神的儀式,觀眾不需要完全看懂《遊林驚夢:巧遇Hagay》,但你能感受心與土地團聚的渴望,也不急著在此處釐清或定義什麼,但你的在場感受,就是一條線索,關於如何找著自己的路徑、自己的聲音。
Thumbnail
這是一場修復文化與重建精神的儀式,觀眾不需要完全看懂《遊林驚夢:巧遇Hagay》,但你能感受心與土地團聚的渴望,也不急著在此處釐清或定義什麼,但你的在場感受,就是一條線索,關於如何找著自己的路徑、自己的聲音。
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News