2017年2月27日 星期一

Linux 檔案IO: 通用的IO模型

檔案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會返回填滿零的空間.









沒有留言:

張貼留言