国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統(tǒng) > Linux > 正文

《Linux/Unix系統(tǒng)編程手冊(cè)》讀書筆記8 (文件I/O緩沖)

2024-06-28 13:26:32
字體:
供稿:網(wǎng)友
《linux/Unix系統(tǒng)編程手冊(cè)》讀書筆記8 (文件I/O緩沖)

《Linux/Unix系統(tǒng)編程手冊(cè)》讀書筆記 目錄

第13章

這章主要將了關(guān)于文件I/O的緩沖。

系統(tǒng)I/O調(diào)用(即內(nèi)核)和C語言標(biāo)準(zhǔn)庫I/O函數(shù)(即stdio函數(shù))在對(duì)磁盤進(jìn)行操作的時(shí)候都會(huì)發(fā)生緩沖。通過緩沖可以在一定程度上將用戶空間與實(shí)際的物理設(shè)備分離,還可以減少內(nèi)核訪問磁盤的次數(shù)。

先來看看關(guān)于內(nèi)核緩沖區(qū)高速緩沖:read和write調(diào)用在對(duì)磁盤文件進(jìn)行操作的時(shí)候不會(huì)直接訪問磁盤,如下圖所示。

例如:write(fd, "abc", 3) write調(diào)用會(huì)將"abc"從用戶空間緩沖區(qū)傳遞內(nèi)核緩沖區(qū)中并隨即返回。在之后的某個(gè)時(shí)刻(緩沖區(qū)滿了或者需要刷新),內(nèi)核會(huì)將其緩沖區(qū)的數(shù)據(jù)寫入到磁盤上,因此write系統(tǒng)調(diào)用與訪問磁盤的操作不是同步執(zhí)行的。同理,對(duì)于read(fd, buffer, 3):內(nèi)核會(huì)從磁盤讀取數(shù)據(jù)并存在內(nèi)核的緩沖區(qū)上,read調(diào)用再從內(nèi)核緩沖區(qū)讀取3個(gè)字節(jié)的數(shù)據(jù)到用戶緩沖區(qū)。當(dāng)緩沖區(qū)的全部數(shù)據(jù)被讀取完,內(nèi)核才會(huì)再從磁盤文件讀取下一段數(shù)據(jù)。

這樣的設(shè)計(jì)可以使得read和write系統(tǒng)調(diào)用不用等待磁盤操作從而加快操作的速度,還減少了內(nèi)核訪問磁盤的次數(shù)。

PS:Linux內(nèi)核對(duì)緩沖區(qū)(內(nèi)核緩沖區(qū))的大小沒有固定的上限,但是可用物理內(nèi)存總量和其他進(jìn)程對(duì)物理內(nèi)存的需求會(huì)影響緩沖區(qū)的大小。

內(nèi)核訪問磁盤的字節(jié)數(shù)是固定的,所以盡量使得每次read(write)傳輸?shù)淖止?jié)數(shù)達(dá)到合適的數(shù)目可以減少系統(tǒng)調(diào)用所消耗的時(shí)間。

下表為書中的一個(gè)關(guān)于復(fù)制100MB大小的文件花費(fèi)的時(shí)間,BUF_SIZE為傳輸?shù)淖止?jié)數(shù), Elapsed為總共的用時(shí),Total CPU為CPU的總共用時(shí),User CPU為用戶CPU的用時(shí),System CPU為系統(tǒng)CPU用時(shí)。測(cè)試的文件系統(tǒng)為塊大小為4096字節(jié)的ext2。

當(dāng)BUF_SIZE為4096字節(jié)的時(shí)候,達(dá)到最優(yōu)性能,再繼續(xù)增大BUF_SIZE不會(huì)對(duì)性能有太大的影響,是因?yàn)橄到y(tǒng)調(diào)用(read和write)花費(fèi)的時(shí)間與在用戶空間和內(nèi)核空間之間傳輸數(shù)據(jù)以及實(shí)際磁盤操作所花費(fèi)的時(shí)間對(duì)比已經(jīng)微不足道。

再來看看第二個(gè)表,是關(guān)于寫入一個(gè)100MB大小的文件所需的時(shí)間。

其實(shí)再進(jìn)行write調(diào)用后并沒有這么快執(zhí)行磁盤I/O,因?yàn)閷?shí)際計(jì)算機(jī)的RAM是很大(測(cè)試環(huán)境是4G),所以結(jié)合前表可以知道復(fù)制文件耗時(shí)絕大部分是用在磁盤的讀取。

接著來看stdio庫的緩沖。

stdio庫的一些函數(shù)(fPRintf, fscanf, fgets, fputs, fgets, fputc, fgetc)會(huì)幫我們自動(dòng)采取大塊數(shù)據(jù)緩沖以減少系統(tǒng)調(diào)用。

通過setvbuf設(shè)置stdio庫函數(shù)的緩沖方式

1 #include <stdio.h>2 3 int setvbuf(FILE *stream, char *buf, int mode, size_t size);

成功調(diào)用返回0,失敗返回非0值。

其中stream為文件流(PS:先打開文件流再調(diào)用setvbuf),buf為使用的緩沖區(qū),size為緩沖區(qū)的大小。當(dāng)buf不為NULL,就指向size大小的內(nèi)存塊作為stream的緩沖區(qū);當(dāng)buf為NULL,stdio庫會(huì)為stream自動(dòng)分配一個(gè)緩沖區(qū)。mode為緩沖的類型。

mode的取值:

_IONBF不對(duì)I/O進(jìn)行緩沖,即立即調(diào)用write和read
_IOLBF采用行緩沖I/O(終端設(shè)備的流的默認(rèn)采用)
_IOFBF 單次讀寫數(shù)據(jù)的大小與緩沖區(qū)相同(磁盤的流默認(rèn)采用)

除了setvbuf還有setbuf和setbuffer

1 #define _BSD_SOURCE   //獲取setbuffer的聲明2 #include <stdio.h>3 4 void setbuf(FILE *stream, char *buf);5 6 void setbuffer(FILE *stream, char *buf, size_t size);7  

還有通過fflush刷新stdio緩沖區(qū)

1 #include <stdio.h>2 3 int fflush(FILE *stream);

成功調(diào)用返回0,失敗返回EOF。

如果stream為NULL,fflush會(huì)刷新所有的緩沖區(qū)。

如果將fflush用在輸入流,可以將已緩沖的輸入數(shù)據(jù)全部丟棄。

在C函數(shù)庫的實(shí)現(xiàn)中,如果stdin和stdout指向同一個(gè)終端,那么從stdin讀取輸入時(shí)都會(huì)隱含調(diào)用fflush(stdout)。

----------------------暫時(shí)省略同步I/O。。。。這部分翻譯的很坑,看不懂。。。。

----------------------還有直接I/O。。。。。。。。。。。。。。。。。。。。。。

下圖為I/O緩沖小結(jié):

練習(xí):

13-5. tail [ -n num ] file 命令打印名為file文件的最后路面行(默認(rèn)為10行)。使用I/O系統(tǒng)調(diào)用(lseek()、read()、write()等)來實(shí)現(xiàn)該命令。

  1 /*  2  * =====================================================================================  3  *  4  *       Filename:  13.5.c  5  *  6  *    Description: 簡單tail實(shí)現(xiàn),可能存在bug,但是沒有找到!!!   7  *  8  *        Version:  1.0  9  *        Created:  2014年05月02日 18時(shí)58分15秒 10  *       Revision:  none 11  *       Compiler:  gcc 12  * 13  *         Author:  alan (), alan19920626@Gmail.com 14  *   Organization:   15  * 16  * ===================================================================================== 17  */ 18  19 #include <sys/stat.h> 20 #include <fcntl.h> 21 #include <ctype.h> 22 #include "tlpi_hdr.h" 23  24 #define BUF_SIZE 4096 25  26 int main(int argc, char *argv[]){ 27     off_t  seek, off, offset = 0; 28     int whence, fd, num, numRead, type = 0, i, off_cnt = 1, n_cnt = 0; 29     Boolean flag = FALSE; 30     struct stat statbuf; 31     char *file; 32     char buf[BUF_SIZE+1]; 33  34     if(strcmp(argv[1], "--help") == 0) 35         usageErr("%s [ -n num ] file", argv[0]); 36  37     //獲取文件名 38     file = argv[1]; 39  40     if(argc == 4 && strcmp(argv[1], "-n") == 0){ 41         flag = TRUE; 42         file = argv[3]; 43     } 44  45     //獲取最后的行數(shù) 46     num = (flag == TRUE) ? getInt(argv[2], GN_GT_0, "num") : 10; 47  48     //打開文件對(duì)應(yīng)的文件描述符 49     fd = open(file, O_RDONLY); 50     if(fd == -1) 51         errExit("open"); 52  53     if(fstat(fd, &statbuf) == -1) 54         errExit("fstat"); 55  56     //判斷文件的大小是否超過4096字節(jié) 57     if(statbuf.st_size <= BUF_SIZE){ 58         off = 0; 59         whence = SEEK_CUR; 60         type = 1; 61     } 62     else{ 63         off = -1 * BUF_SIZE; 64         whence = SEEK_END; 65     } 66     67     //根據(jù)換行符判斷行數(shù) 68     while((seek = lseek(fd, off_cnt * off, whence)) != -1){ 69         numRead = read(fd, buf, BUF_SIZE); 70         if(numRead == -1) 71             errExit("read"); 72         if(numRead > 0){ 73             for(i = numRead-1; i >=0; --i){ 74                 if(buf[i] == '/n') 75                     n_cnt++; 76                 if(n_cnt == num+1) 77                     break; 78             } 79              80             if(n_cnt == num+1){ 81                 offset += (numRead-1 - i); 82                 break; 83             } 84             else 85                 offset += numRead; 86             if(type) 87                 break;     //如果行數(shù)小于要求的,當(dāng)文件的偏移量回到文件的開始位置,即buf從數(shù)組結(jié)尾回到數(shù)組的頭部時(shí),跳出循環(huán)。 88         } 89         off_cnt++; 90         memset(buf, 0, BUF_SIZE+1); 91     } 92     if(seek == -1) 93         errExit("lseek"); 94      95     if(lseek(fd, (0 - offset), SEEK_END) == -1) 96         errExit("lseek"); 97  98     while((numRead = read(fd, buf, BUF_SIZE)) > 0){ 99         buf[numRead] = '/0';100         printf("%s", buf);101         memset(buf, 0, BUF_SIZE+1);102     }103     if(numRead == -1)104         errExit("read");105 106     exit(EXIT_SUCCESS);107 }

測(cè)試結(jié)果:

一、

lancelot@debian:~/Code/tlpi$ ./13.5 13.5.c     while((numRead = read(fd, buf, BUF_SIZE)) > 0){        buf[numRead] = '/0';        printf("%s", buf);        memset(buf, 0, BUF_SIZE+1);    }    if(numRead == -1)        errExit("read");    exit(EXIT_SUCCESS);}lancelot@debian:~/Code/tlpi$ tail 13.5.c     while((numRead = read(fd, buf, BUF_SIZE)) > 0){        buf[numRead] = '/0';        printf("%s", buf);        memset(buf, 0, BUF_SIZE+1);    }    if(numRead == -1)        errExit("read");    exit(EXIT_SUCCESS);}

二、

lancelot@debian:~/Code/tlpi$ tail -n 15 13.5.c         errExit("lseek");        if(lseek(fd, (0 - offset), SEEK_END) == -1)        errExit("lseek");    while((numRead = read(fd, buf, BUF_SIZE)) > 0){        buf[numRead] = '/0';        printf("%s", buf);        memset(buf, 0, BUF_SIZE+1);    }    if(numRead == -1)        errExit("read");    exit(EXIT_SUCCESS);}lancelot@debian:~/Code/tlpi$ ./13.5 -n 15 13.5.c         errExit("lseek");        if(lseek(fd, (0 - offset), SEEK_END) == -1)        errExit("lseek");    while((numRead = read(fd, buf, BUF_SIZE)) > 0){        buf[numRead] = '/0';        printf("%s", buf);        memset(buf, 0, BUF_SIZE+1);    }    if(numRead == -1)        errExit("read");    exit(EXIT_SUCCESS);}

---------------多點(diǎn)使用系統(tǒng)調(diào)用和庫函數(shù)才會(huì)熟練,只要熟練就編程才不會(huì)覺得很難上手啊。。。。。。

---------------另外那篇關(guān)于動(dòng)態(tài)規(guī)劃的算法導(dǎo)論學(xué)習(xí)記錄感覺寫不下去了。。。。。。。。。。。。。。

---------------繼續(xù)努力!!!!!!


發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 新建县| 潼关县| 信丰县| 迭部县| 平凉市| 河西区| 寿阳县| 喀喇沁旗| 馆陶县| 阜康市| 武隆县| 焉耆| 遂宁市| 彭阳县| 荥阳市| 环江| 上饶县| 阜城县| 班玛县| 宿迁市| 弥渡县| 鄱阳县| 溧水县| 马鞍山市| 靖西县| 玉环县| 镇赉县| 鹤庆县| 静海县| 湘潭市| 江陵县| 康平县| 龙陵县| 金乡县| 临沧市| 库尔勒市| 云霄县| 沾化县| 阳春市| 波密县| 靖州|