Linux Chapter 4 - 檔案IO
檔案I/O
概述
全部執行I/O的系統呼叫都是透過檔案描述符來控制開啟的檔案,各類型的檔案在開啟之後,都能以檔案描述符進行操控。
標準檔案符
shell平時會將以下三個檔案描述符保持一直開啟,可以使用I/O redirection進行適當的修改
| file descriptor | 用途 | POSIX 名稱 | stdio stream |
|---|---|---|---|
| 0 | 標準輸入 | STDIN_FILENO | stdin |
| 1 | 標準輸出 | STDOUT_FILENO | stdout |
| 2 | 標準錯誤 | STDERR_FILENO | stderr |
開啟檔案
open()
|
|
flags -> 為位元mask 指定檔案的存取模式
mode -> 指定了檔案的存取權限(如果open()沒有指定O_CREATflags可以省略)
- 由於flags各個參數互相獨立(除了必選項不可重複)皆可以使用
|來新增性質
必選項:以下三個常數中必須指定一個,且僅允許指定一個。
| flags | 用途 |
|---|---|
| O_RDONLY | 以唯讀模式開啟 |
| O_WRONLY | 以唯寫模式開啟 |
| O_RDWR | 以讀寫模式開啟 |
以可讀寫方式打開文件。上述三種旗標是互斥的,也就是不可同時使用,但可與下列的旗標利用OR(|)運算符組合。
以下可選項可以同時指定0個或多個,和必選項按位|起來作為flags參數。
| flags | 用途 |
|---|---|
| O_CLOEXEC | 設定close-on-exec flags |
| O_CREAT | 若檔案不存在則建立 |
| O_DIRECTORY | 如果pathname不是目錄,失敗 |
| O_EXCL | 結合O_CREAT參數使用,專門用來建立檔案,若創建文件時,文件已存在,會返回錯誤訊息 |
| O_LARGEFILE | 在32位元系統中使用,可以開啟大檔案 |
| O_NOCTTY | 不要讓pathname所指向的終端設備,成為控制終端機 |
| O_NOFOLLOW | 如果參數pathname 所指的文件為一符號連接,則會令打開文件失敗 |
| O_TRUNC | 若文件存在並且以可寫的方式打開時,此旗標會令文件長度清為0,而原來存於該文件的資料也會消失。 |
| O_APPEND | 總在檔案結尾新增資料 |
| O_ASYNC | 進行I/O操作時,產生signal |
| O_DIRECT | 檔案I/O跳過 buffer cache |
| O_DSYNC | 提供同步I/O的資料完整性 |
| O_NOATIME | 在read()時不更新最近的存取時間 |
| O_NONBLOCK | 以非阻塞的方式開啟 |
| O_SYNC | 以同步的方式寫入檔案 |
詳細內容可以參考The linux programming interface 國際中文版p.84
man page : https://man7.org/linux/man-pages/man2/open.2.html
創建檔案
creat() 根據pathname建立並開啟一個檔案,若檔案存在=>開啟並清空檔案內容
|
|
可以等價於以下的open()函數
|
|
讀取檔案
read()
|
|
count 指定最多可以讀取的byte數量 buffer 提供用來存放輸入資料的buffer cache位址 buffer cache至少有count個bytes
man page : https://man7.org/linux/man-pages/man2/read.2.html
寫入檔案
write()
|
|
count 指定最多可以要從buffer寫入檔案的byte數量 buffer 要寫入檔案的資料bytes數
關閉檔案
|
|
改變檔案偏移量
有時候也稱為讀寫偏移量或指標。指的是執行下一個read() or write()操作的檔案位置。檔案開啟時或指向開頭(偏移量 = 0) 針對fd參數所代表的已開啟檔案,可以使用lseek() function
|
|
offset指定以byte為單位的數值,whence表示應參考哪個基準點來解釋offset參數,如下列表格
| whence | 用途 |
|---|---|
| SEEK_SET | 將檔案偏移量從檔案的起始點開始算 offset 個 bytes |
| SEEK_CUR | 相對於目前的偏移量,調整offset個 bytes |
| SEEK_END | 將檔案偏移量設定為檔案大小加上offset 個 bytes,可以說offset應從檔案最後一個byte之後的下一個byte開始算起 |
一些lseek()的應用案例
|
|
lseek()不允許應用於pipe,FIFO,socket or terminal
檔案空洞(file hole)
如果檔案偏移量跨越了檔案結尾,然後再執行I/O操作,read()會return 0,但write()可以在檔案結尾後任意寫資料進去。
從檔案結尾之後到新寫入資料之間的這段空間就稱為檔案空洞。
- 檔案空洞不佔用任何空間,優勢在於相較於為實際需要的空bytes分配磁碟區塊,稀疏填充的檔案會佔用較少的空間。
以下為apue範例
|
|
running result
|
|
可以使用du -h 指令 => 顯示檔案佔用的block是多少