檔案IO: 通用的IO模型
file descriptor:
全部執行IO操作的系統呼叫都是透過file descriptor去存取. 通常是一個非負的整數.每個process都有一組自己的file descriptor
一般process都會有以下三個file descriptor, 他們由繼承shell而來
file descriptor
|
用途
|
POSIX name
|
stdio stream
|
0
|
標準輸入
|
STDIN_FILENO
|
stdin
|
1
|
標準輸出
|
STDOUT_FILENO
|
stdout
|
2
|
標準錯誤
|
STDERR_FILENO
|
stderr
|
對於檔案呼叫IO操作有四個主要操作
- open
- read
- write
- close
這四個操作可以對於所有檔案進行IO操作, 包含terminial之類的裝置
open()
int open(const char *pathname, int flags, .../* mode_t mode*/);
- flag: 位元遮罩, 指定檔案的存取模式
- mode: 指定檔案的存取權限(存取權限除了mode之外還會受到process的umask和parent目錄的預設存取權限的影響)
open呼叫返回的值是目前process中最小的未用的file descriptor
open flag簡易表格
Flag
|
用途
|
O_RDONLY
|
以唯讀模式開啟
|
O_WRONLY
|
以唯寫模式開啟
|
O_RDWR
|
以讀寫模式開啟
|
O_CLOEXEC
|
設定close-on-exec旗幟, 可以免去程式執行fcntl()的F_GETED和F_SETFD格外的操作, 可以避免race condition
|
O_CREAT
|
若檔案不存在則建立之
|
O_DIRECTORY
|
若pathname不是目錄則失敗
|
O_EXCL
|
結合O_CREAT參數使用, 專門用於建立檔案, 若檔案存在了就不會開啟檔案.
|
O_LARGEFILE
|
在32位元系統使用此旗幟開啟大檔案
|
O_NOCTTY
|
不要讓pathname成為控制終端機
|
O_NOFOLLOW
|
對符號連結不予解參考
|
O_TRUNC
|
截斷現存的檔案, 使其長度為零. 若檔案存在且為普通檔案, 會將檔案清空並檔案大小設為0
|
O_APPEND
|
總在檔案結尾附加上資料
|
O_ASYNC
|
當IO操作可行時ㄝ, 產生signal通知process(在linux中沒有實質的效果)
|
O_DIRECT
|
檔案IO跳過buffer cache
|
O_DSYNC
|
提供同步的IO資料完整性
|
O_NOATIME
|
read()時不更新最近的access time
|
O_NONBLOCK
|
以非阻塞方式開啟
|
O_SYNC
|
以同步的方式寫入檔案
|
create(pathname) 等同於 open(pathanme, O_WRONLY | O_CREAT | O_TRUNC)
open()呼叫的錯誤
Error Name
|
說明
|
EACCES
|
檔案權限不允許process以flags所指頂的方式開啟
|
EISDIR
|
所指定的檔案為目錄且呼叫者企圖寫入操作
|
EMFILE
|
Process所開啟file descriptor已達上限
|
ENFILE
|
檔案開啟的數量已達系統上限
|
ENOENT
|
檔案不存在
|
EROFS
|
所屬檔案是唯讀檔卻以寫入模式開啟
|
ETXTBSY
|
所指檔案是執行檔且正在執行
|
read()
ssize_t read(int fd, void *buffer, size_t count)
- count: 最多能讀取的byte數(size_t是無號整數型別)
- buffer: 放讀到資料的空間
- 返回實際讀到的byte數, 失敗反為-1
- 遇到EOF則返回0
- 遇到讀到的byte數比指定少的情形
- 到檔案結尾
- 從終端機讀到’\n’字元
write()
ssize_t write(int fd, const volid *buffer, size_t count)
- count: 最多能寫入的byte數(size_t是無號整數型別)
- buffer: 放寫入資料的空間
- 當write操作成功後也不能保證資料被寫到Disk上, 因為kernel對於disk的IO操作有做buffer cache
close()
int close(int fd)
關閉沒有用的file descriptor是良好的習慣
lseek()
移動寫入或讀取file的入口
off_t lseek(int fd, off_t offset, int whence)
- offset: 指定了一個以byte為單位的數值, 表從基準點移動的距離. 從下一個byte開始算.
- whence: 參考的基準點
- SEEK_SET: 從檔案起始byte
- SEEK_CUR:目前檔案存取的地方
- SEEK_END:檔案最後一個byte
若whence為SEEK_CUR or SEEK_END, offset可以為負數. 但為SEEK_SET就不能為負數
lseek()不允許用到pipe, FIFO, socket or 終端機等裝置上. 但可以用在disk上
file hole
write()可以允許在檔案結尾寫上資料, 而利用lseek()方式可以在檔案結尾offset處開始寫資料, 檔案結尾到新寫上的資料中間的空間稱之為file hole(檔案空洞). 讀file hold會返回填滿零的空間.
沒有留言:
張貼留言