不帶緩沖的I/O
。術語不帶緩沖
指的是在用戶的進程中對其不會自動緩沖,每個read和write都調用內核中的一個系統調用。但是,所有磁盤I/O都要經過內核的塊緩存區(也稱為內核的緩沖區高速緩存)。唯一例外的是對原始磁盤設備的I/O。
#include <fcntl.h>
int open(const char *path, int oflag, ... /* mode_t mode */ );
int openat(int fd, const char *path, int oflag, ... /* mode_t mode */ );
Both return: file descriptor if OK, −1 on error
oflag參數
- 以下5個常量必須指定一個且只能指定一個O_RDONLY、O_WRONLY、O_RDWR、O_EXEC(只執行打開)、O_SEARCH(只搜索打開,應用于目錄,尚未支持)
- 下列常量則可選O_APPEND、O_CLOEXEC、O_CREAT(需要指定第3個參數mode)、O_EXCL、O_DIRECTORY、O_NOFOLLOW、O_NONBLOCK、O_SYNC、O_TRUNC
open和openat函數返回的文件描述符一定是最小的未用描述符數值。這一點被某些應用程序用來在標準輸入、標準輸出或標準錯誤上打開新的文件。
fd參數把open和openat函數區分開,共有3種可能性
- path參數指定的是絕對路徑名,則fd參數被忽略,openat函數相當于open函數
- path參數指定的是相對路徑名,則fd參數指出了相對路徑名在文件系統中的開始地址。fd參數是通過打開相對路徑名所在的目錄來獲取
- path參數指定了相對路徑名,而fd參數具有特殊值
AT_FDCWD
,則路徑名在當前工作目錄中獲取
openat函數是POSIX.1最新版本中新增的一類函數之一,希望解決兩個問題:
- 讓線程可以使用相對路徑名打開目錄中的文件,而不再只能打開當前工作目錄
- 可以避免time-of-check-to-time-of-use(TOCTTOU)錯誤
TOCTTOU錯誤的基本思想是:
指計算機系統的資料與權限等狀態的檢查與使用之間,因為特定狀態在這段時間已發生改變所產生的軟件漏洞
文件名和路徑名截斷
#include <fcntl.h>
int creat(const char *path, mode_t mode);
Returns: file descriptor opened for write-only if OK, −1 on error
#include <unistd.h>
int close(int fd);
Returns: 0 if OK, −1 on error
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
Returns: new file offset if OK, −1 on error
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t nbytes);
Returns: number of bytes read, 0 if end of file, −1 on error
- 讀普通文件時,到達文件尾端
- 從終端設備讀時,通常一次最多讀一行
- 從網絡讀時,網絡中的緩沖機制可能造成返回值小于所要求讀的字節數
- 從管道或FIFO讀時,如若管道包含的字節少于所需的數量,那么read將只返回實際可用的字節數
- 從某些面向記錄的設備(如磁帶)讀時,一次最多返回一個記錄
- 當一信號造成中斷,而已經讀了部分數據量時
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t nbytes);
Returns: number of bytes written if OK, −1 on error
內核使用3種數據結構表示打開文件,它們之間的關系決定了在文件共享方面一個進程對另一個進程可能產生的影響
左邊:進程級的文件描述符表
- 文件描述符標志,目前只有一個FD_CLOEXEC
- 指向一個文件表項的指針
中間:系統級的打開文件表:每次調用open打開一個文件新增一個文件表項(不同進程可打開同一個文件,導致多個文件表項)
- 文件狀態標志(讀、寫、添寫、同步、非阻塞等,受open時指定的oflag參數影響,也可通過fcntl函數指定FD_SETFL改變)
- 當前文件偏移量
- 指向該文件v節點表項的指針
右邊:文件系統級的i-node表
- i節點包含文件的相關信息,如文件的所有者、文件長度、指向文件實際數據塊在磁盤上所在位置的指針等。
- linux沒有v節點,而是采用了一個通用i節點。無論是v節點還是通用i節點,它們都是指向一個與文件系統相關的i節點
其他
- 完成write之后,文件表項的當前文件偏移量增加所寫入的字節數。如果這導致當前文件偏移量超出了文件長度,則將i節點表項中的當前文件長度設置為當前文件偏移量
- 如果通過O_APPEND標志打開一個文件,則相應標志會設置到文件表項的文件狀態標志中。每次執行寫操作之前,當前文件偏移量會首先被設置為i節點表項中的文件長度
- lseek函數只修改文件表項中的當前文件偏移量,不進行任何I/O操作。
- 注意:文件描述符標志只作用于一個進程的一個文件描述符,而文件狀態標志則作用于指向該文件表項的任何進程中的所有描述符
對open函數指定O_CREAT和O_EXCL
函數PRead、pwrite
#include <unistd.h>
ssize_t pread(int fd, void *buf, size_t nbytes, off_t offset);
Returns: number of bytes read, 0 if end of file, −1 on error
ssize_t pwrite(int fd, const void *buf, size_t nbytes, off_t offset);
新聞熱點
疑難解答