開始本章學(xué)習(xí)之前了解一些概念:
1画恰、帶緩存和不帶緩存IO
參考
系統(tǒng)調(diào)用财喳,用戶程序通過系統(tǒng)級別API調(diào)用系統(tǒng)函數(shù)將請求傳遞給內(nèi)核侄榴。無緩存的IO表示在用戶層沒有緩存遭贸,每次讀寫都需要調(diào)用系統(tǒng)函數(shù)戈咳,頻繁調(diào)用系統(tǒng)函數(shù)效率是比較低的。但值得注意的是壕吹,并不是說調(diào)用了系統(tǒng)函數(shù)就會將數(shù)據(jù)寫道磁盤著蛙,這樣效率會更低,內(nèi)核中有緩沖存儲器耳贬,只有數(shù)據(jù)滿了時才會寫道磁盤踏堡。同理,為了不讓每次讀寫操作都直接調(diào)用系統(tǒng)函數(shù)咒劲,將內(nèi)容寫道用戶設(shè)置的緩存區(qū)中顷蟆,有三種常用緩存:
- 全緩存诫隅。當(dāng)填滿標(biāo)準(zhǔn)I/O緩存后才執(zhí)行I/O操作。磁盤上的文件通常是全緩存的帐偎。
- 行緩存逐纬。當(dāng)輸入輸出遇到新行符或緩存滿時,才由標(biāo)準(zhǔn)I/O庫執(zhí)行實際I/O操作肮街。stdin风题、stdout通常是行緩存的。
- 無緩存嫉父。相當(dāng)于read沛硅、write了。stderr通常是無緩存的绕辖,因為它必須盡快輸出摇肌。
帶緩存IO也叫標(biāo)準(zhǔn)IO,目的就是減少調(diào)用read和write的次數(shù)仪际。舉個例子围小,寫數(shù)據(jù)到文件上,內(nèi)核緩存(注意這個不是用戶層緩存區(qū))區(qū)長度是100字節(jié)树碱,我們調(diào)用不帶緩存的IO函數(shù)write()就要調(diào)用10次(加入每次10字節(jié))肯适,這樣系統(tǒng)效率低,現(xiàn)在我們在用戶層建立另一個緩存區(qū)(用戶層緩存區(qū)或者叫流緩存)成榜,假設(shè)流緩存的長度是50字節(jié)框舔,我們用標(biāo)準(zhǔn)C庫函數(shù)的fwrite()將數(shù)據(jù)寫入到這個流緩存區(qū)里面,流緩存區(qū)滿50字節(jié)后在進入內(nèi)核緩存區(qū)赎婚,此時再調(diào)用系統(tǒng)函數(shù)write()將數(shù)據(jù)寫入到文件(實質(zhì)是磁盤)上刘绣,看到這里,你用該明白一點挣输,標(biāo)準(zhǔn)IO操作fwrite()最后還是要掉用無緩存IO操作write,這里進行了兩次調(diào)用fwrite()寫100字節(jié)也就是進行兩次系統(tǒng)調(diào)用write()纬凤。
0、open close函數(shù)
1撩嚼、lseek函數(shù)
文件偏移量概念停士,每個文件打開的位置和當(dāng)前內(nèi)容位置為偏移量,
off_t lseek(int filedes, off_t offset, int whence); 返回值:新的偏移量(成功)完丽,-1(失斚虼伞)
參數(shù) offset 的含義取決于參數(shù) whence
1. 如果 whence 是 SEEK_SET,文件偏移量將被設(shè)置為 offset舰涌。
2. 如果 whence 是 SEEK_CUR猖任,文件偏移量將被設(shè)置為 cfo 加上 offset,
offset 可以為正也可以為負(fù)瓷耙。
3. 如果 whence 是 SEEK_END朱躺,文件偏移量將被設(shè)置為文件長度加上 offset刁赖,
offset 可以為正也可以為負(fù)。
SEEK_SET长搀、SEEK_CUR 和 SEEK_END 是 System V 引入的宇弛,在這之前使用的是 0、1 和 2源请。
lseek 的以下用法返回當(dāng)前的偏移量:
off_t currpos;
currpos = lseek(fd, 0, SEEK_CUR);
這個技巧也可用于判斷我們是否可以改變某個文件的偏移量枪芒。如果參數(shù) fd(文件描述符)指定的是 pipe(管道)、FIFO 或者 socket谁尸,lseek 返回 -1 并且置 errno 為 ESPIPE舅踪。
2、read write函數(shù)
3良蛮、文件原子操作待理解
4抽碌、復(fù)制文件描述符
dup和dup2也是兩個非常有用的調(diào)用,它們的作用都是用來復(fù)制一個文件的描述符决瞳。它們經(jīng)常用來重定向進程的stdin货徙、stdout和stderr。這兩個函數(shù)的 原形如下:
#include <unistd.h> int dup( int oldfd ); int dup2( int oldfd, int targetfd )
利用函數(shù)dup皮胡,我們可以復(fù)制一個描述符痴颊。傳給該函數(shù)一個既有的描述符,它就會返回一個新的描述符屡贺,這個新的描述符是傳給它的描述符的拷貝蠢棱。這意味著,這兩個描述符共享同一個數(shù)據(jù)結(jié)構(gòu)烹笔。例如,如果我們對一個文件描述符執(zhí)行l(wèi)seek操作抛丽,得到的第一個文件的位置和第二個是一樣的谤职。
int oldfd;
oldfd = open("app_log", (O_RDWR | O_CREATE), 0644 );
dup2( oldfd, 1 );
close( oldfd );
本例中,我們打開了一個新文件亿鲜,稱為“app_log”允蜈,并收到一個文件描述符,該描述符叫做fd1蒿柳。我們調(diào)用dup2函數(shù)饶套,參數(shù)為oldfd和1,這會導(dǎo)致用我們新打開的文件描述符替換掉由1代表的文件描述符(即stdout垒探,因為標(biāo)準(zhǔn)輸出文件的id為1)妓蛮。任何寫到stdout的東西,現(xiàn)在都將改為寫入名為“app_log”的文件中圾叼。需要注意的是蛤克,dup2函數(shù)在復(fù)制了oldfd之后捺癞,會立即將其關(guān)閉,但不會關(guān)掉新近打開的文件描述符构挤,因為文件描述符1現(xiàn)在也指向它髓介。
5、sync筋现、fsync唐础、fdatasync
我們知道,內(nèi)核中設(shè)有高速緩存或頁高速緩存矾飞,大多數(shù)磁盤IO都通過緩沖區(qū)進行一膨。也叫延遲寫,當(dāng)內(nèi)核需要重用緩沖區(qū)時凰慈,會先把緩存中的數(shù)據(jù)寫入磁盤汞幢,避免丟失,要用到上面幾個函數(shù)微谓。
6森篷、fcntl
學(xué)習(xí)
主要有以下功能: