apue 第三章 文件I/O
文件描述符
- 對(duì)于內(nèi)核刹前,所有打開的文件都通過文件描述符引用
- STDIN_FILEOUT,STDOUT_FILEOUT,STDERR_FILEOUT,0宋雏,1,2是unix系統(tǒng)shell的標(biāo)準(zhǔn)文件描述符
文件偏移量 lseek
- 每一個(gè)打開的文件都有一個(gè)相關(guān)的文件偏移量雏掠,文件的讀寫操作都是從偏移量開始的
- lseek可以設(shè)置文件的偏移量,返回設(shè)置后的偏移量纽绍,如果文件描述符指向的是一個(gè)管道署拟,網(wǎng)絡(luò)套接字婉宰,不能設(shè)置偏移量返回-1
- 返回當(dāng)前文件偏移量,還可以檢測(cè)當(dāng)前文件描述符能否設(shè)置偏移量
#include "apue.h"
int
main(void)
{
if (lseek(STDIN_FILENO, 0, SEEK_CUR) == -1)
printf("cannot seek\n");
else
printf("seek OK \n");
exit(0);
}
- 如果設(shè)置的偏移量大于當(dāng)前文件的長(zhǎng)度推穷,對(duì)文件的下一次寫會(huì)加長(zhǎng)文件心包,沒有寫的字節(jié)置為0, 形成一個(gè) 空洞,可能會(huì)引起磁盤使用的增加
IO效率
- 進(jìn)程關(guān)閉時(shí),會(huì)關(guān)閉所打開的文件描述符
- 大多數(shù)文件系統(tǒng)在讀取文件會(huì)采取某種預(yù)讀技術(shù),試圖讀入比緩沖區(qū)更多的數(shù)據(jù)到內(nèi)存中。所以讀入某些大小緩沖區(qū)的數(shù)據(jù)消耗時(shí)間是差不多的馒铃。
文件共享 相關(guān)資料:p61
- 內(nèi)核使用3種數(shù)據(jù)結(jié)構(gòu)表示打開文件蟹腾,他們之間的關(guān)系決定了在文件共享時(shí),一個(gè)文件對(duì)另外一個(gè)文件的影響
- 每個(gè)進(jìn)程在進(jìn)程表中都有一個(gè)進(jìn)程表項(xiàng),包含了一張進(jìn)程打開文件的 文件描述表 包含了打開的 文件描述符標(biāo)志 ,指向一個(gè)文件表項(xiàng)的 指針
- 內(nèi)核為每個(gè)打開的文件維護(hù)了一張文件表( 文件表項(xiàng) ) 包含了文件的 狀態(tài)標(biāo)志(讀区宇,寫岭佳,等), 當(dāng)前文件的 偏移量 ,指向該文件的 V節(jié)點(diǎn)表項(xiàng) 指針
-
V節(jié)點(diǎn) 包含了文件信息和文件的操作函數(shù)指針,同時(shí)包含了 i節(jié)點(diǎn)(存儲(chǔ)文件長(zhǎng)度)
原子操作問題
- 進(jìn)程A B共同寫一個(gè)文件,有2個(gè)文件表項(xiàng),但是共享一個(gè)v節(jié)點(diǎn)。A調(diào)用lseek設(shè)置偏移量為1500,內(nèi)核切換進(jìn)程B,也設(shè)置1500偏移量,然后B調(diào)用wrtie寫100字節(jié)數(shù)據(jù)萧锉,偏移量變?yōu)?600,i節(jié)點(diǎn)的文件長(zhǎng)度更新為1600。此時(shí)A的文件偏移量還是1500述寡,調(diào)用write寫數(shù)據(jù)柿隙,就會(huì)把B的數(shù)據(jù)覆蓋
- 在這過程中,先定位到文件的尾端(lseek),然后寫(write),使用的是2個(gè)不同的函數(shù)鲫凶,在這2個(gè)函數(shù)調(diào)用之間內(nèi)核可能會(huì)掛起進(jìn)程禀崖,去執(zhí)行另外一個(gè)進(jìn)程∶牛可以在打開文件的時(shí)候設(shè)置 O_APPEND 標(biāo)志波附,每次寫操作前,都將當(dāng)期偏移量設(shè)置到文件的末尾
-
原子操作 是指由多步執(zhí)行的一個(gè)操作昼钻,則要么執(zhí)行完所有操作掸屡,要么一步也不執(zhí)行
dup dup2
- dup 和 dup2可以復(fù)制一個(gè)文件描述符,文件描述符共享同一個(gè)文件表項(xiàng),包括文件狀態(tài)標(biāo)志,當(dāng)前文件偏移量然评。
- dup2可以顯示的指定文件描述符值
sync fsync
- 向文件寫入數(shù)據(jù),數(shù)據(jù)會(huì)先寫入緩沖區(qū)(頁高速緩存)仅财,然后排入隊(duì)列,依次寫入磁盤,這種方式稱為延遲寫
-
sync 會(huì)將緩沖區(qū)的數(shù)據(jù)排入隊(duì)列就結(jié)束碗淌,不等待寫入磁盤盏求,內(nèi)核會(huì)有一個(gè)update定時(shí)調(diào)用sync抖锥,定時(shí)沖洗緩沖區(qū)
-
fsync 只對(duì)文件描述符fb的文件起作用,寫磁盤結(jié)束才返回
fcntl
- fcntl 可以改變或獲取文件的描述符和狀態(tài)標(biāo)志,這在無法得到shell打開的文件名時(shí)很有用,只需要知道描述符,就修改屬性
#include "apue.h"
#include <fcntl.h>
int
main(int argc, char *argv[])
{
int val;
if (argc != 2)
err_quit("usage: a.out <descriptor#>");
if ((val = fcntl(atoi(argv[1]), F_GETFL, 0)) < 0)
err_sys("fcntl error for fd %d", atoi(argv[1]));
switch (val & O_ACCMODE) {
case O_RDONLY:
printf("read only");
break;
case O_WRONLY:
printf("write only");
break;
case O_RDWR:
printf("read write");
break;
default:
err_dump("unknown access mode");
}
if (val & O_APPEND)
printf(", append");
if (val & O_NONBLOCK)
printf(", nonblocking");
if (val & O_SYNC)
printf(", synchronous writes");
#if !defined(_POSIX_C_SOURCE) && defined(O_FSYNC) && (O_FSYNC != O_SYNC)
if (val & O_FSYNC)
printf(", synchronous writes");
#endif
putchar('\n');
exit(0);
}
- 1:標(biāo)準(zhǔn)輸入 2:標(biāo)準(zhǔn)輸出 3:錯(cuò)誤 5:shell <>:標(biāo)識(shí)用文件描述符5打開數(shù)據(jù)
- 在使用fctnl修改文件描述符或文件狀態(tài)值時(shí),需要先獲得現(xiàn)在的標(biāo)志值,然后按照期望修改
- 通過使用fsync 或者改變文件狀態(tài)標(biāo)志位O_SYNC時(shí)可以獲得 延遲寫
out :
? lesson_3 ./a.out 0</dev/tty
read only
? lesson_3 ./a.out 1>temp.foo
? lesson_3 cat temp.foo
write only
? lesson_3 ./a.out 2 2>>temp.foo
write only, append
? lesson_3 ./a.out 5 5<>temp.foo
read write
最后編輯于 :
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者