版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
第9章嵌入式文件I/O編程9.1Linux系統(tǒng)調(diào)用及用戶編程接口一、系統(tǒng)調(diào)用
Linux內(nèi)核中設(shè)置了一組用于實現(xiàn)各種系統(tǒng)功能的子程序,稱為系統(tǒng)調(diào)用。用戶可以通過系統(tǒng)調(diào)用命令在自己的應(yīng)用程序中調(diào)用它們。系統(tǒng)調(diào)用由操作系統(tǒng)核心提供,運行于核心態(tài);而普通的函數(shù)調(diào)用由函數(shù)庫或用戶自己提供,運行于用戶態(tài)。二者在使用方式上也有相似之處。
Linux的系統(tǒng)調(diào)用大約有250個,按功能邏輯可分為:進程控制、進程間的通信、文件系統(tǒng)控制、存儲管理、網(wǎng)絡(luò)管理、套接字控制、用戶管理等幾類。二、用戶編程接口
系統(tǒng)調(diào)用并不直接與程序員進行交互,它僅僅通過軟中斷機制向內(nèi)核提交請求來獲取內(nèi)核提供的接口。實際程序員是調(diào)用的是用戶編程接口(API)。API函數(shù)并不是與系統(tǒng)調(diào)用都一一對應(yīng),有時一個API函數(shù)會需要幾個系統(tǒng)調(diào)用來共同完成函數(shù)的功能,甚至還有一些API函數(shù)不需要調(diào)用相應(yīng)的系統(tǒng)調(diào)用(因此它所完成的不是內(nèi)核提供的服務(wù))。
三、Linux中文件及文件描述符
Linux中文件分為4種:普通文件、目錄文件、鏈接文件和設(shè)備文件。
文件描述符是一個非負整數(shù)。當(dāng)打開一個現(xiàn)存文件或創(chuàng)建一個新文件時,內(nèi)核向進程返回一個文件描述符。當(dāng)讀、寫一個文件時,open或creat用返回的文件描述符標(biāo)識該文件,將其作為參數(shù)傳送給read或write。9.2底層文件I/O操作文件I/O操作的系統(tǒng)調(diào)用,主要用到5個函數(shù):open、read、write、lseek和close。這些函數(shù)的特點是不帶緩存,直接對文件(包括設(shè)備)進行讀寫操作。一、基本文件操作1、open()用于打開或創(chuàng)建文件。所需頭文件#include<sys/types.h>//提供類型pid_t的定義#include<sys/stat.h>#include<fcntl.h>函數(shù)原型intopen(constchar*pathname,flags,intperms)函數(shù)原型intopen(constchar*pathname,flags,intperms)函數(shù)傳入值pathname被打開的文件名(可包括路徑名)flag:文件打開的方式O_RDONLY:只讀方式打開文件O_WRONLY:可寫方式打開文件O_RDWR:讀寫方式打開文件O_CREAT:如果該文件不存在,就創(chuàng)建一個新的文件,并用第三個參數(shù)為其設(shè)置權(quán)限O_EXCL:如果使用O_CREAT時文件存在,則可返回錯誤消息。這一參數(shù)可測試文件是否存在O_NOCTTY:使用本參數(shù)時,如文件為終端,那么終端不可以作為調(diào)用open()系統(tǒng)調(diào)用的那個進程的控制終端O_TRUNC:如文件已經(jīng)存在,并且以只讀或只寫成功打開,那么會先全部刪除文件中原有數(shù)據(jù)O+APPEND:以添加方式打開文件,在打開文件的同時,文件指針指向文件的末尾perms被打開文件的存取權(quán)限,為8進制表示法函數(shù)返回值成功:返回文件描述符失敗:-1flag參數(shù)可通過“|”組合構(gòu)成,但前3個函數(shù)不能相互組合。perms是被打開文件的存取權(quán)限可用一組宏定義:S_I(R/W/X)(USR/GRP/OTH)或用8進制數(shù)表示。2、close()用于關(guān)閉文件。所需頭文件#include<unistd.h>函數(shù)原型intclose(intfd)函數(shù)輸入值fd:文件描述符函數(shù)返回值0:成功-1:出錯3、read用于從指定文件讀取數(shù)據(jù)放到緩存區(qū)。所需頭文件#include<unistd.h>函數(shù)原型ssize_tread(intfd,void*buf,size_tcount)函數(shù)傳入值fd:文件描述符buf:指定存儲器讀出數(shù)據(jù)的緩沖區(qū)count:指定讀出的字節(jié)數(shù)函數(shù)返回值成功:讀到的字節(jié)數(shù)0:已到達文件尾-1:出錯4、write用于向指定文件寫數(shù)據(jù),寫操作從文件的當(dāng)前位移量處開始。所需頭文件#include<unistd.h>函數(shù)原型ssize_twrite(intfd,void*buf,size_tcount)函數(shù)傳入值fd:文件描述符buf:指定存儲器寫入數(shù)據(jù)的緩沖區(qū)count:指定讀出的字節(jié)數(shù)函數(shù)返回值成功:已寫的字節(jié)數(shù)-1:出錯5、lseek函數(shù)是用于在指定的文件描述符中將文件指針定位到相應(yīng)的位置。所需頭文件#include<unistd.h>#include<sys/types.h>函數(shù)原型off_tlseek(intfd,off_toffset,intwhence)函數(shù)傳入值fd:文件描述符offset:偏移量,每一讀寫操作所需要移動的距離,單位是字節(jié)的數(shù)量,可正可負(向前移,向后移)whence:當(dāng)前位置的基點SEEK_SET:當(dāng)前位置為文件的開頭,新位置為偏移量的大小SEEK_CUR:當(dāng)前位置為文件指針的位置,新位置為當(dāng)前位置加上偏移量SEEK_END:當(dāng)前位置為文件的結(jié)尾,新位置為文件的大小加上偏移量的大小函數(shù)返回值成功:文件的當(dāng)前位移-1:出錯6、函數(shù)使用實例該示例程序首先文件,然后對此文件進行讀寫操作(記得要將文件打開屬性改為可讀寫,將文件權(quán)限也做相應(yīng)更改)。接著,寫入“Hello!I'mwritingtothisfile!”,此時文件指針位于文件尾部。接著在使用lseek函數(shù)將文件指針移到文件開始處,并讀出10個字節(jié)并將其打印出來。/*write.c*/#include<unistd.h>#include<sys/types.h>#include<sys/stat.h>#include<fcntl.h>#include<stdlib.h>#include<stdio.h>#include<string.h>#defineMAXSIZEintmain(void){inti,fd,size,len;char*buf="Hello!I'mwritingtothisfile!";charbuf_r[10];len=strlen(buf);/*返回字符串長度*//*首先調(diào)用open函數(shù),并指定相應(yīng)的權(quán)限*/if((fd=open("/tmp/hello.c",O_CREAT|O_TRUNC|O_RDWR,0666))<0){perror(“open:”);/*打印出錯信息字符串*/exit(1);/*結(jié)束進程執(zhí)行*/}elseprintf(“openfile:hello.c%d\n”,fd);:”);/*格式化輸出數(shù)據(jù)*//*調(diào)用write函數(shù),將buf中的內(nèi)容寫入到打開的文件中*/if((size=write(fd,buf,len))<0){perror("write:");exit(1);}elseprintf("Write:%s\n",buf);/*調(diào)用lsseek函數(shù)將文件指針移到文件起始,并讀出文件中的10個字節(jié)*/lseek(fd,0,SEEK_SET);if((size=read(fd,buf_r,10))<0){perror("read:");exit(1);}elseprintf("readformfile:%s\n",buf_r);if(close(fd)<0){perror("close:");exit(1);}elseprintf("Closehello.c\n");exit(0);}二、文件鎖
當(dāng)多個用戶共同使用、操作一個文件的情況下,Linux通常采用的方法是給文件上鎖,來避免共享的資源產(chǎn)生競爭的狀態(tài)。文件鎖包括建議性鎖和強制性鎖。建議性鎖要求每個上鎖文件的進程都要檢查是否有鎖存在,并且尊重已有的鎖。強制性鎖是由內(nèi)核執(zhí)行的鎖,當(dāng)一個文件被上鎖進行寫入操作的時候,內(nèi)核將阻止其他任何文件對其進行讀寫操作。實現(xiàn)文件上鎖的函數(shù)有flock和fcntl,其中flock用于對文件施加建議性鎖,而fcntl不僅可以施加建議性鎖,還可以施加強制鎖。同時,fcntl還能對文件的某一記錄進行上鎖,也就是記錄鎖。1、fcntl()函數(shù)格式所需頭文件#include<sys/types.h>#include<unistd.h>#include<fcntl.h>函數(shù)原型intfcnt1(intfd,intcmd,structflock*lock)函數(shù)傳入值fd:文件描述符cmdF_DUPFD:復(fù)制文件描述符F_GETFD:獲得fd的close-on-exec標(biāo)志,若標(biāo)志未設(shè)置,則文件經(jīng)過exec函數(shù)之后仍保持打開狀態(tài)F_SETFD:設(shè)置close-on-exec標(biāo)志,該標(biāo)志以參數(shù)arg的FD_CLOEXEC位決定F_GETFL:得到open設(shè)置的標(biāo)志F_SETFL:改變open設(shè)置的標(biāo)志F_GETFK:根據(jù)lock描述,決定是否上文件鎖F_SETFK:設(shè)置lock描述的文件鎖F_SETLKW:這是F_SETLK的阻塞版本(命令名中的W表示等待(wait))。如果存在其他鎖,則調(diào)用進程睡眠;如果捕捉到信號則睡眠中斷Lock:結(jié)構(gòu)為flock,設(shè)置記錄鎖的具體狀態(tài),后面會詳細說明函數(shù)返回值成功:0-1:出錯Structflock{shortl_type;off_tl_start;shortl_whence;off_tl_len;pid_tl_pid;}第三個參數(shù)flock結(jié)構(gòu)定義:flock結(jié)構(gòu)中每個變量的取值含義如表:l_typeF_RDLCK:讀取鎖(共享鎖)F_WRLCK:寫入鎖(排斥鎖)F_UNLCK:解鎖l_stat相對位移量(字節(jié))l_whence:SEEK_SET:當(dāng)前位置為文件的開頭,新位置為偏移量的大小.SEEK_CUR:當(dāng)前位置為文件指針的位置,新位置為當(dāng)前位置加上偏移量SEEK_END:當(dāng)前位置為文件的結(jié)尾,新位置為文件的大小加上偏移量的大小。l_len加鎖區(qū)域的長度I_pid具有阻塞當(dāng)前進程的鎖/*lock_set函數(shù)*/voidlock_set(intfd,inttype){structflocklock;lock.l_whence=SEEK_SET;//賦值lock結(jié)構(gòu)體lock.l_start=0;lock.l_len=0;while(1){lock.l_type=type;/*根據(jù)不同的type值給文件上鎖或解鎖*/if((fcntl(fd,F_SETLK,&lock))==0){if(lock.l_type==F_RDLCK)printf("readlocksetby%d\n",getpid());elseif(lock.l_type==F_WRLCK)printf("writelocksetby%d\n",getpid());elseif(lock.l_type==F_UNLCK)printf("releaselockby%d\n",getpid());return;}/*判斷文件是否可以上鎖*/fcntl(fd,F_GETLK,&lock);/*判斷文件不能上鎖的原因*/if(lock.l_type!=F_UNLCK){/*/該文件已有寫入鎖*/if(lock.l_type==F_RDLCK)printf("readlockalreadysetby%d\n",lock.l_pid);/*該文件已有讀取鎖*/elseif(lock.l_type==F_WRLCK)printf("writelockalreadysetby%d\n",lock.l_pid);getchar();}}}三、多路復(fù)用1、I/O處理的模型有5種:阻塞I/O模型:在這種模型下,若所調(diào)用的I/O函數(shù)沒有完成相關(guān)的功能就會使進程掛起,直到相關(guān)數(shù)據(jù)到才會返回。如常見對管道設(shè)備、終端設(shè)備和網(wǎng)絡(luò)設(shè)備進行讀寫時經(jīng)常會出現(xiàn)這種情況。非阻塞模型:在這種模型下,當(dāng)請求的I/O操作不能完成時,則不讓進程睡眠,而且返回一個錯誤。非阻塞I/O使用戶可以調(diào)用不會永遠阻塞的I/O操作,如open、write和read。如果該操作不能完成,則會立即出錯返回,且表示該I/O如果繼續(xù)執(zhí)行就會阻塞?!/O多路轉(zhuǎn)接模型:在這種模型下,如果請求的I/O操作阻塞,且它不是真正阻塞I/O,而是讓其中的一個函數(shù)等待,在這期間,I/O還能進行其他操作。如本節(jié)要介紹的select函數(shù)和poll函數(shù),就是屬于這種模型。信號驅(qū)動I/O模型:在這種模型下,通過安裝一個信號處理程序,系統(tǒng)可以自動捕獲特定信號的到來,從而啟動I/O。這是由內(nèi)核通知用戶何時可以啟動一個I/O操作決定的。異步I/O模型:在這種模型下,當(dāng)一個描述符已準(zhǔn)備好,可以啟動I/O時,進程會通知內(nèi)核?,F(xiàn)在,并不是所有的系統(tǒng)都支持這種模型。2、select函數(shù)格式select可以具體設(shè)置每一個所關(guān)心的文件描述符的條件、希望等待的時間等,從select函數(shù)返回時,內(nèi)核會通知用戶已準(zhǔn)備好的文件描述符的數(shù)量、已準(zhǔn)備好的條件等。通過使用select返回值,就可以調(diào)用相應(yīng)的I/O處理函數(shù)了。所需頭文件#include<sys/types.h>#include<sys/time.h>#include<unistd.h>函數(shù)原型intselect(intnumfds,fd_set*readfds,fd_set*writefds,fd_set*exeptfds,structtimeval*timeout)Select函數(shù)的語法格式如函數(shù)原型intselect(intnumfds,fd_set*readfds,fd_set*writefds,fd_set*exeptfds,structtimeval*timeout)函數(shù)傳入值numfds:需要檢查的號碼最高的文件描述符加1readfds:由select()監(jiān)視的讀文件描述符集合writefds:由select()監(jiān)視的寫文件描述符集合exeptfds:由select()監(jiān)視的異常處理文件描述符集合timeoutNULL:永遠等待,直到捕捉到信號或文件描述符已準(zhǔn)備好為止具體值:structtimeval類型的指針,若等待為timeout時間還沒有文件描符準(zhǔn)備好,就立即返回0:從不等待,測試所有指定的描述符并立即返回函數(shù)返回值成功:準(zhǔn)備好的文件描述符-1:出錯FD_ZERO(fd_set*set)清除一個文件描述符集FD_SET(intfd,fd_set*set)將一個文件描述符加入文件描述符集中FD_CLR(intfd,fd_set*set)將一個文件描述符從文件描述符集中清除FD_ISSET(intfd,fd_set*set)測試該集合中的一個給定位是否有變化
一般來說,在使用select函數(shù)之前,首先使用FD_ZERO和FD_SET來初始化文件描述符集,在使用了select函數(shù)時,可循環(huán)使用FD_ISSET測試描述符集,在執(zhí)行完對相關(guān)后文件描述符后,使用FD_CLR來清楚描述符集。select文件描述符處理函數(shù)select函數(shù)中的timeout是一個structtimeval類型的指針,該結(jié)構(gòu)體如下所示:structtimeval{longtv_sec;/*second*/longtv_unsec;/*andmicroseconds*/}可以看到,這個時間結(jié)構(gòu)體的精確度可以設(shè)置到微秒級,這對于大多數(shù)的應(yīng)用而言已經(jīng)足夠了。本實例中主要實現(xiàn)將文件hello1里的內(nèi)容讀出,并將此內(nèi)容每隔10s寫入hello2中去。在這里建立了兩個描述符集,其中一個描述符集inset1是用于讀取文件內(nèi)容,另一個描述符集inset2是用于寫入文件的。兩個文件描述符fds[0]和fds[1]分別指向這一文件描述符。在首先初始化完各文件描述符集之后,就開始了循環(huán)測試這兩個文件描述符是否可讀寫,由于在這里沒有阻塞,所以文件描述符處于準(zhǔn)備就緒的狀態(tài)。這時,就分別對文件描述符fds[0]和fsd[1]進行讀寫操作/*select.c*/#include<fcntl.h>#include<stdio.h>#include<unistd.h>#include<stdlib.h>#include<time.h>intmain(void){intfds[2];charbuf[7];inti,rc,maxfd;fd_setinset1,inset2;structtimevaltv;/*首先按一定的權(quán)限打開hello1文件*/if((fds[0]=open("hello1",O_RDWR|O_CREAT,0666))<0)perror("openhello1");/*再按一定的權(quán)限打開hello2文件*/if((fds[1]=open("hello2",O_RDWR|O_CREAT,0666))<0)perror("openhello2");if((rc=write(fds[0],"Hello!\n",7)))printf("rc=%d\n",rc);lseek(fds[0],0,SEEK_SET);/*取出兩個文件描述符中的較大者*/maxfd=fds[0]>fds[1]?fds[0]:fds[1];/*初始化讀集合inset1,并在讀集合中加入相應(yīng)的描述集*/FD_ZERO(&inset1);FD_SET(fds[0],&inset1);/*初始化寫集合inset2,并在寫集合中加入相應(yīng)的描述集*/FD_ZERO(&inset2);FD_SET(fds[1],&inset2);tv.tv_sec=2;tv.tv_usec=0;/*循環(huán)測試該文件描述符是否準(zhǔn)備就緒,并調(diào)用select函數(shù)對相關(guān)文件描述符做對應(yīng)操作*/while(FD_ISSET(fds[0],&inset1)||FD_ISSET(fds[1],&inset2)){if(select(maxfd+1,&inset1,&inset2,NULL,&tv)<0)perror("select");else{if(FD_ISSET(fds[0],&inset1)){rc=read(fds[0],buf,7);if(rc>0){buf[rc]='\0';printf("read:%s\n",buf);}elseperror("read");}if(FD_ISSET(fds[1],&inset2)){rc=write(fds[1],buf,7);if(rc>0){buf[rc]='\0';printf("rc=%d,write:%s\n",rc,buf);}elseperror("write");sleep(10);}}}exit(0);}四、標(biāo)準(zhǔn)I/O開發(fā)
前面幾節(jié)所述的文件及I/O讀寫都是基于文件描述符的。這些都是基本的I/O控制,是不帶緩存的。而本節(jié)所要討論的I/O操作都是基于流緩沖的,它是符合ANSIC的標(biāo)準(zhǔn)I/O處理。
標(biāo)準(zhǔn)I/O提供流緩沖的目的是盡可能減少使用read和write調(diào)用的數(shù)量。標(biāo)準(zhǔn)I/O提供了3種類型的緩沖存儲。全緩沖。在這種情況下,當(dāng)填滿標(biāo)準(zhǔn)I/O緩存后才進行實際I/O操作。行緩沖。在這種情況下,當(dāng)在輸入和輸出中遇到新行符時,標(biāo)準(zhǔn)I/O庫執(zhí)行I/O操作。這允許我們一次輸出一個字符(如fputc函數(shù)),但只有寫了一行之后才進行實際I/O操作。不帶緩沖。標(biāo)準(zhǔn)I/O庫不對字符進行緩沖。如果用標(biāo)準(zhǔn)I/O函數(shù)寫若干字符到不帶緩沖的流中,則相當(dāng)于用write函數(shù)將這些字符全寫到被打開文件上。1、打開文件函數(shù)打開文件有三個標(biāo)準(zhǔn)函數(shù),分別為:fopen、fdopen和freopen。它們可以以不同的模式打開,但都返回一個指向FILE的指針,該指針指向?qū)?yīng)的I/O流。此后,對文件的讀寫都是通過這個FILE指針來進行。其中fopen可以指定打開文件的路徑和模式,fdopen可以指定打開的文件描述符和模式,而freopen除可指定打開的文件、模式外,還可指定特定的I/O流。所需頭文件#include<stdio.h>函數(shù)原型FILE*fopen(constchar*path,constchar*mode)函數(shù)傳入值path:包含要打開的文件路徑及文件名mode:文件打開狀態(tài)(后面會具體說明)函數(shù)返回值成功:指向FILE的指針失?。篘ULLfopen函數(shù)格式fdopen函數(shù)格式所需頭文件#include<stdio.h>函數(shù)原型FILE*fdopen(intfd,constchar*mode)函數(shù)傳入值fd:要打開的文件描述符mode:文件打開狀態(tài)(后面會具體說明)函數(shù)返回值成功:指向FILE的指針失敗:NULLfreopen函數(shù)格式所需頭文件#include<stdio.h>函數(shù)原型FILE*freopen(constchar*path,constchar*mode,FILE*stream)函數(shù)傳入值path:包含要打開的文件路徑及文件名mode:文件打開狀態(tài)(后面會具體說明)stream:已打開的文件指針函數(shù)返回值成功:指向FILE的指針失?。篘ULL2、關(guān)閉文件函數(shù)fclose()所需頭文件#include<stdio.h>函數(shù)原型intfclose(FILE*stream)函數(shù)傳入值stream:已打開的文件指針函數(shù)返回值成功:0失?。篍OF3、讀文件函數(shù))fread()所需頭文件#include<stdio.h>函數(shù)原型size_tfre
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025版生態(tài)保護與修復(fù)工程勘察設(shè)計合同3篇
- 2024年網(wǎng)絡(luò)安全防護服務(wù)與合作合同
- 二零二五年信息技術(shù)合同認定登記流程優(yōu)化方案3篇
- 2025版離婚后子女撫養(yǎng)權(quán)及教育費用分?jǐn)倕f(xié)議書3篇
- 2024年生態(tài)環(huán)境保護諒解協(xié)議
- 課題申報書:代際差異視角下中老年夾心世代的代際照料及其福利效應(yīng)研究
- 課題申報書:促進多學(xué)科交叉研究的治理模式改革與實踐路徑研究
- 課題申報書:超大城市應(yīng)急治理中公眾參與的助推機制及助推策略研究
- 2024年選礦工藝租賃承包及維護合同版B版
- 2025版旋轉(zhuǎn)燈箱廣告投放及效果評估合同3篇
- 《基于單片機的送餐機器人定位功能設(shè)計》9800字(論文)
- 產(chǎn)品經(jīng)理100道面試題
- 胡頹子育苗技術(shù)規(guī)程-地方標(biāo)準(zhǔn)修訂說明
- 2024年度施工員(市政工程)專業(yè)技能知識考試題庫及答案(共四套)
- 2024年金融理財-金融理財師(AFP)考試近5年真題附答案
- 數(shù)字資產(chǎn)管理與優(yōu)化考核試卷
- 教案-“枚舉法”信息技術(shù)(信息科技)
- 2024年內(nèi)部審計年度工作計劃范文(六篇)
- 四川省成都市2021-2022學(xué)年物理高一下期末學(xué)業(yè)質(zhì)量監(jiān)測模擬試題含解析
- 新教科版六年級上冊科學(xué)全冊知識點(期末總復(fù)習(xí)資料)
- 綠色建筑工程監(jiān)理實施細則
評論
0/150
提交評論