當(dāng)前位置:首頁 > 嵌入式 > 嵌入式軟件
[導(dǎo)讀] 不帶緩存的文件I/O 操作,主要用到5 個函數(shù):open、read、write、lseek和close。這里的不帶緩存是指每一個函數(shù)都只調(diào)用系統(tǒng)中的一個函數(shù)(不理解這句話的含義)。這些函數(shù)雖

 不帶緩存的文件I/O 操作,主要用到5 個函數(shù):open、read、write、lseek和close。這里的不帶緩存是指每一個函數(shù)都只調(diào)用系統(tǒng)中的一個函數(shù)(不理解這句話的含義)。這些函數(shù)雖然不是ANSI C的組成部分,但是是POSIX 的組成部分。

open函數(shù)語法要點(diǎn)

|-- #i nclude // 提供類型pid_t的定義

所需頭文件----|-- #i nclude

|-- #i nclude

函數(shù)原型 int open(const char *pathname,flags,int perms)

pathname 被打開的文件名(可包括路徑名)

O_RDONLY:只讀方式打開文件

O_WRONLY:可寫方式打開文件

O_RDWR:讀寫方式打開文件

O_CREAT:如果該文件不存在,就創(chuàng)建一個新的文件,并用第三個參數(shù)為其設(shè)置權(quán)限

O_EXCL:如果使用O_CREAT時文件存在,則可返回錯誤消息。這一

函數(shù)傳入值 參數(shù)可測試文件是否存在

O_NOCTTY:使用本參數(shù)時,如文件為終端

終端不可用open()系統(tǒng)調(diào)用的那個進(jìn)程的控制終端

O_TRUNC:如文件已經(jīng)存在,并且以只讀或只寫成功打開,那么會先

全部刪除文件中原有數(shù)據(jù)

O+APPEND:以添加方式打開文件,在打開文件的同時,文件指針指

向文件的末尾

perms 被打開文件的存取權(quán)限,為8進(jìn)制表示法

函數(shù)返回值 成功:返回文件描述符

失?。?1

補(bǔ)述:文件描述符

對于Linux 而言,所有對設(shè)備和文件的操作都使用文件描述符來進(jìn)行的。文件描述符

是一個非負(fù)的整數(shù),它是一個索引值,并指向內(nèi)核中每個進(jìn)程打開文件的記錄表。當(dāng)打開一

個現(xiàn)存文件或創(chuàng)建一個新文件時,內(nèi)核就向進(jìn)程返回一個文件描述符;當(dāng)需要讀寫文件時,

也需要把文件描述符作為參數(shù)傳遞給相應(yīng)的函數(shù)。

通常,一個進(jìn)程啟動時,都會打開3 個文件:標(biāo)準(zhǔn)輸入、標(biāo)準(zhǔn)輸出和標(biāo)準(zhǔn)出錯處理。這

3 個文件分別對應(yīng)文件描述符為0、1 和2(也就是宏替換STDIN_FILENO、STDOUT_FILENO

和STDERR_FILENO)。

基于文件描述符的I/O 操作雖然不能移植到類Linux 以外的系統(tǒng)上去(如Windows),但它

往往是實(shí)現(xiàn)某些I/O操作的惟一途徑,如Linux中低級文件操作函數(shù)、多路I/O、TCP/IP套接字

編程接口等。同時,它們也很好地兼容POSIX標(biāo)準(zhǔn),因此,可以很方便地移植到任何POSIX平

臺上。基于文件描述符的I/O操作是Linux中最常用的操作之一。

read函數(shù)語法要點(diǎn)

所需頭文件 #i nclude

函數(shù)原型 ssize_t read(int fd,void *buf,size_t count)

fd:文件描述符

函數(shù)傳入值 buf:指定存儲器讀出數(shù)據(jù)的緩函數(shù)傳入值 沖區(qū)

count:指定讀出的字節(jié)數(shù)

成功:讀到的字節(jié)數(shù)

函數(shù)返回值 0:已到達(dá)文件尾

-1:出錯

write函數(shù)語法要點(diǎn)

所需頭文件 #i nclude

函數(shù)原型 ssize_t write(int fd,void *buf,size_t count)

fd:文件描述符

函數(shù)傳入值 buf:指定存儲器寫入數(shù)據(jù)的緩函數(shù)傳入值 沖區(qū)

count:指定讀出的字節(jié)數(shù)

函數(shù)返回值 成功:已寫的字節(jié)數(shù)

-1:出錯

lseek函數(shù)語法要點(diǎn)

所需頭文件 #i nclude

#i nclude

函數(shù)原型 off_t lseek(int fd,off_t offset,int whence)

fd:文件描述符

函數(shù)傳入值 offset:偏移量,每一讀寫操作所需要移動的距離

單位是字節(jié)的數(shù)量,可正可負(fù)(向前移,向后移)

whence: SEEK_SET:當(dāng)前位置為文件的開頭,新位置為偏移量的大小

當(dāng)前位置 SEEK_CUR:當(dāng)前位置為文件指針的位置,新位置為當(dāng)前位置加上偏移

的基點(diǎn) SEEK_END:當(dāng)前位置為文件的結(jié)尾,新位置為文件的大小加上偏移

函數(shù)返回值 成功:文件的當(dāng)前位移

-1:出錯

/*打開,關(guān)閉,讀寫文件.c*/

#i nclude unistd.h>

#i nclude sys/types.h>

#i nclude sys/stat.h>

#i nclude fcntl.h>

#i nclude stdlib.h>

#i nclude stdio.h>

int main(void)

{

int fd; //文件描述符

int i,size,len;

char *buf="Writing to this file!";

char buf_r[10];

len = strlen(buf);

/*調(diào)用open函數(shù),以可讀寫的方式打開,注意選項(xiàng)可以用“|”符號連接*/

if((fd = open("/tmp/hello.c", O_CREAT | O_TRUNC | O_WRONLY , 0600 ))0){

perror("open:");

exit(1);

}

else{

printf("Open file: hello.c %d\n",fd);

}

/*調(diào)用write函數(shù),將buf中的內(nèi)容寫入到打開的文件中*/

if((size = write( fd, buf, len)) 0){

perror("write:");

exit(1);

}

else

printf("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);

}

else

printf("read form file:%s\n",buf_r);

if( close(fd) 0 ){

perror("close:");

exit(1);

}

else

printf("Close hello.c\n");

exit(0);

}

當(dāng)多個用戶共同使用、操作一個文件的情況,這時,Linux 通常采用的方法是給文件上鎖,來避免共享的資源產(chǎn)生競爭的狀態(tài)。

文件鎖包括建議性鎖和強(qiáng)制性鎖。建議性鎖要求每個上鎖文件的進(jìn)程都要檢查是否有鎖存在,并且尊重已有的鎖。在一般情況下,內(nèi)核和系統(tǒng)都不使用建議性鎖。強(qiáng)制性鎖是由內(nèi)核執(zhí)行的鎖,當(dāng)一個文件被上鎖進(jìn)行寫入操作的時候,內(nèi)核將阻止其他任何文件對其進(jìn)行讀寫操作。采用強(qiáng)制性鎖對性能的影響很大,每次讀寫操作都必須檢查是否有鎖存在。在Linux 中,實(shí)現(xiàn)文件上鎖的函數(shù)有l(wèi)ock和fcntl,其中flock用于對文件施加建議性鎖,而fcntl不僅可以施加建議性鎖,還可以施加強(qiáng)制鎖。同時,fcntl還能對文件的某一記錄進(jìn)行[!--empirenews.page--]

上鎖,也就是記錄鎖。記錄鎖又可分為讀取鎖和寫入鎖,其中讀取鎖又稱為共享鎖,它能夠使多個進(jìn)程都能在

文件的同一部分建立讀取鎖。而寫入鎖又稱為排斥鎖,在任何時刻只能有一個進(jìn)程在文件的某個部分上建立寫入鎖。當(dāng)然,在文件的同一部分不能同時建立讀取鎖和寫入鎖。

fcntl函數(shù)格式

fcntl函數(shù)可以改變已經(jīng)打開文件的性質(zhì)。

#i nclude

#i nclude

#i nclude

int fcntl(int filedes, int cmd, ... ) ;

返回:若成功則依賴于cmd(見下),若出錯為- 1。

f c n t l函數(shù)有五種功能:

n 復(fù)制一個現(xiàn)存的描述符, 新文件描述符作為函數(shù)值返(c m d=F_DUPFD)。

n 獲得/設(shè)置文件描述符標(biāo)記,對應(yīng)于filedes 的文件描述符標(biāo)志作為函數(shù)值返回.(c m d = F_GETFD或F_SETFD)。

n 獲得/設(shè)置文件狀態(tài)標(biāo)志,對應(yīng)于filedes 的文件狀態(tài)標(biāo)志作為函數(shù)值返回。(c m d = F_GETFL或F_SETFL)。

n 獲得/設(shè)置異步I / O有權(quán)(c m d = F_GETOWN或F_SETOWN)。

n 獲得/設(shè)置記錄鎖(c m d = F_SETLK , F_SETLKW)。

關(guān)于加鎖和解鎖區(qū)域的說明還要注意下列各點(diǎn):

l 該區(qū)域可以在當(dāng)前文件尾端處開始或越過其尾端處開始,但是不能在文件起始位置之前開始或越過該起始位置。

l 如若l_len為0,則表示鎖的區(qū)域從其起點(diǎn)(由l_start和l_whence決定)開始直至最大可能位置為止。也就是不管添寫到該文件中多少數(shù)據(jù),它都處于鎖的范圍。

l 為了鎖整個文件,通常的方法是將l_start說明為0,l_whence說明為SEEK_SET,l_len說明為0。

實(shí)例:

/*fcntl_write.c測試文件寫入鎖主函數(shù)部分*/

#i nclude unistd.h>

#i nclude sys/file.h>

#i nclude sys/types.h>

#i nclude sys/stat.h>

#i nclude stdio.h>

#i nclude stdlib.h>

/*lock_set函數(shù)*/

void lock_set(int fd, int type)

{

struct flock lock;

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("read lock set by %d\n",getpid());

else if( lock.l_type == F_WRLCK )

printf("write lock set by %d\n",getpid());

else if( lock.l_type == F_UNLCK )

printf("release lock by %d\n",getpid());

return;

}

/*判斷文件是否可以上鎖*/

fcntl(fd, F_GETLK,&lock);

/*判斷文件不能上鎖的原因*/

if(lock.l_type != F_UNLCK)

{

/*/該文件已有寫入鎖*/

if( lock.l_type == F_RDLCK )

printf("read lock already set by %d\n",lock.l_pid);

/*該文件已有讀取鎖*/

else if( lock.l_type == F_WRLCK )

printf("write lock already set by %d\n",lock.l_pid);

getchar();

}

}

}

int main(void)

{

int fd;

/*首先打開文件*/

fd=open("hello",O_RDWR | O_CREAT, 0666);

if(fd 0)

{

perror("open");

exit(1);

}

/*給文件上寫入鎖*/

lock_set(fd, F_WRLCK);

getchar();

/*給文件接鎖*/

lock_set(fd, F_UNLCK);

getchar();

close(fd);

exit(0);

}

開兩個終端分別運(yùn)行,可看到先運(yùn)行的那個終端,成功上鎖,后運(yùn)行的那個無效??梢妼懭腈i是互斥鎖,一個時候只能有一個寫入鎖存在

select 實(shí)現(xiàn)I/O復(fù)用

I/O處理的五種模型

① 阻塞I/O模型:若所調(diào)用的I/O函數(shù)沒有完成相關(guān)的功能就會使進(jìn)程掛起,直到相關(guān)數(shù)據(jù)到達(dá)才會返回。如:終端、網(wǎng)絡(luò)設(shè)備的訪問。

② 非阻塞模型:當(dāng)請求的I/O操作不能完成時,則不讓進(jìn)程休眠,而且返回一個錯誤。如:open、read、write訪問。

③ I/O多路轉(zhuǎn)接模型:如果請求的I/O 操作阻塞,且他不是真正阻塞I/O,而且讓其中的一個函數(shù)等待,在這期間, I/O還能進(jìn)行其他操作。如:select函數(shù)。

④ 信號驅(qū)動I/O模型:在這種模型下,通過安裝一個信號處理程序,系統(tǒng)可以自動捕獲特定信號的到來,從而啟動I/O。

⑤ 異步I/O模型:在這種模型下,當(dāng)一個描述符已準(zhǔn)備好,可以啟動I/O時,進(jìn)程會通知內(nèi)核。由內(nèi)核進(jìn)行后續(xù)處理,這種用法現(xiàn)在較少。

select函數(shù)

傳向select的參數(shù)告訴內(nèi)核:

(1) 我們所關(guān)心的描述符。

(2) 對于每個描述符我們所關(guān)心的條件(是否讀一個給定的描述符?是否想寫一個給定的描述符?是否關(guān)心一個描述符的異常條件?)。

(3) 希望等待多長時間(可以永遠(yuǎn)等待,等待一個固定量時間,或完全不等待)。

從s e l e c t返回時,內(nèi)核告訴我們:

(1) 已準(zhǔn)備好的描述符的數(shù)量。

(2) 哪一個描述符已準(zhǔn)備好讀、寫或異常條件。

#i nclude /* fd_set data type */

#i nclude /* struct timeval */

#i nclude /* function prototype might be here */

int select (int numfds, fd_set *readfds,

fd_set *writefds, fd_set *exceptfds, struct timeval * timeout) ;

返回:準(zhǔn)備就緒的描述符數(shù),若超時則為0,若出錯則為- 1。

timeout值:

n NULL:永遠(yuǎn)等待,直到捕捉到信號或文件描述符已準(zhǔn)備好為止;

n 具體值: struct timeval 類型的指針,若等待為timeout時間還沒有文件描述符準(zhǔn)備好,就立即返回;

n 0:從不等待,測試所有指定 的描述符并立即返回;

先說明最后一個參數(shù),它指定愿意等待的時間。[!--empirenews.page--]

struct timeval

{

long tv_sec; /* seconds */

long tv_usec; /* and microseconds */

};

select函數(shù)根據(jù)希望進(jìn)行的文件操作對文件描述符進(jìn)行分類處理,這里,對文件描述符的處理主要設(shè)計(jì)4個宏函數(shù):

FD_ZERO(fd_set *set) 清除一個文件描述符集;

FD_SET(int fd, fd_set *set) 將一個文件描述符加入文件描述符集中;

FD_CLR(int fd, fd_set *set) 將一個文件描述符從文件描述符集中清除;

FD_ISSET(int fd, fd_set *set) 測試該集中的一個給定位是否有變化;

在使用select函數(shù)之前,首先使用FD_ZERO和FD_SET來初始化文件描述符集,并使用select函數(shù)時,可循環(huán)使用FD_ISSET測試描述符集, 在執(zhí)行完成對相關(guān)的文件描述符后, 使用FD_CLR來清除描述符集。

實(shí)例

/*select.c*/

#i nclude fcntl.h>

#i nclude stdio.h>

#i nclude unistd.h>

#i nclude stdlib.h>

#i nclude sys/time.h>

int main(void)

{

int fds[2];

char buf[7];

int i,rc,maxfd;

fd_set inset1,inset2;

struct timeval tv;

if((fds[0] = open ("hello1", O_RDWR|O_CREAT,0666))0)

perror("open hello1");

if((fds[1] = open ("hello2", O_RDWR|O_CREAT,0666))0)

perror("open hello2");

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);

}else

perror("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);

}else

perror("write");

sleep(10);

}

}

}

exit(0);

}

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

加利福尼亞州圣克拉拉縣2024年8月30日 /美通社/ -- 數(shù)字化轉(zhuǎn)型技術(shù)解決方案公司Trianz今天宣布,該公司與Amazon Web Services (AWS)簽訂了...

關(guān)鍵字: AWS AN BSP 數(shù)字化

倫敦2024年8月29日 /美通社/ -- 英國汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動 BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時企業(yè)卻面臨越來越多業(yè)務(wù)中斷的風(fēng)險,如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報(bào)道,騰訊和網(wǎng)易近期正在縮減他們對日本游戲市場的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會開幕式在貴陽舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點(diǎn): 有效應(yīng)對環(huán)境變化,經(jīng)營業(yè)績穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤率延續(xù)升勢 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競爭力 堅(jiān)持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競爭優(yōu)勢...

關(guān)鍵字: 通信 BSP 電信運(yùn)營商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺與中國電影電視技術(shù)學(xué)會聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會上宣布正式成立。 活動現(xiàn)場 NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會上,軟通動力信息技術(shù)(集團(tuán))股份有限公司(以下簡稱"軟通動力")與長三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉