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