日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux高级编程--05.文件读写

發(fā)布時間:2023/12/19 linux 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux高级编程--05.文件读写 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

緩沖I/O和非緩沖I/O

文件讀寫主要牽涉到了如下五個操作:打開、關(guān)閉、讀、寫、定位。在Linux系統(tǒng)中,提供了兩套API,

  • 一套是C標準API:fopen、fclose、fread、fwrite、fseek,
  • 另一套則是POSIX定義的系統(tǒng)API:open、close、read、write、seek。

其中POSIX定義的API是系統(tǒng)API,而C標準API是基于系統(tǒng)API的封裝,并且提供了額外的緩沖的功能。因此也可以把它們叫做緩沖I/O函數(shù)和非緩沖I/O函數(shù)。

除了前面介紹的這幾個緩沖IO函數(shù)外,C標準庫里面還提供了一系列封裝的IO函數(shù):如puts、putchar、printf等。

為什么要有增加緩沖區(qū)這個功能呢?主要是因為IO操作時,操作系統(tǒng)要從用戶態(tài)轉(zhuǎn)換為內(nèi)核態(tài)的,而這個轉(zhuǎn)換過程相對來說比較慢,因此可以通過緩沖的形式減少轉(zhuǎn)換到內(nèi)核態(tài)的次數(shù)。

那么,緩沖IO函數(shù)又是如何工作的呢?

  • 當用fopen打開文件時,除了分配文件句柄外,還額外申請了一個緩沖區(qū)。
  • 讀文件時,會首先讀到緩沖區(qū)中,然后返回用戶需要的部分,多余的部分仍然放在緩沖區(qū),下次再讀的時候可以直接從緩沖區(qū)中返回。
  • 寫文件時,會先寫到緩沖區(qū)中,等緩沖區(qū)滿后再統(tǒng)一寫到文件中。

那么,我們該如何選擇哪一組I/O函數(shù)呢?

  • 非緩沖I/O函數(shù)每次讀寫都要進內(nèi)核,調(diào)一個系統(tǒng)調(diào)用比調(diào)一個用戶空間的函數(shù)要慢很多,所以在用戶空間開辟I/O緩沖區(qū)還是必要的。
  • 用緩沖I/O庫函數(shù)要時刻注意I/O緩沖區(qū)和實際文件有可能不一致,在必要時需調(diào)用fflush()。

I/O函數(shù)也用于讀寫設(shè)備,比如終端或網(wǎng)絡(luò)設(shè)備。此時通常需要更快的響應(yīng),一般不使用緩沖I/O函數(shù)。

PS:嚴格來講,就算是POSIX的I/O函數(shù),仍然是有內(nèi)核I/O緩沖的,所以write也不一定是直接寫到文件的,也可能寫到內(nèi)核I/O緩沖區(qū)中,至于究竟寫到了文件中還是內(nèi)核緩沖區(qū)中對于進程來說是沒有太大差別的,我們不用太關(guān)注這一點。

阻塞I/O和非阻塞I/O

文件讀寫通常有阻塞和非阻塞兩種方式,其中阻塞方式是我們比較常見的一種方式,此時函數(shù)會阻塞至操作完成。例如,對于如下一個等待用戶輸入字符串,并在屏幕上輸出的例子:

#include <unistd.h> #include <stdlib.h>int main(void) {char buf[10];int n = read(STDIN_FILENO, buf, 10);write(STDOUT_FILENO, buf, n);return 0; }

執(zhí)行該函數(shù)時,read函數(shù)會一直阻塞到在屏幕上輸入數(shù)據(jù)并回車(此時STDIN有數(shù)據(jù)可用)為止。
阻塞IO有一個很大的問題是:無法實現(xiàn)并發(fā)。當同時進行多個IO操作的時候,前面的文件數(shù)據(jù)不可用的時候(往往是Socket之類的IPC操作),后面的IO操作無法執(zhí)行。
非阻塞IO則可以很好的解決這個問題,要使用非阻塞IO操作,需要在open的時候制定O_NONBLOCK標志。這樣,如果設(shè)備暫時沒有數(shù)據(jù)可讀就返回-1,調(diào)用者應(yīng)該試著再讀一次(again)。這種行為方式稱為輪詢(Poll),調(diào)用者只是查詢一下,而不是阻塞在這里死等,這樣可以同時監(jiān)視多個設(shè)備:

#include <unistd.h> #include <fcntl.h> #include <stdlib.h>int main(void) {char buf[10];int fd, n;fd = open("/dev/tty", O_RDONLY|O_NONBLOCK);while (1){n = read(fd, buf, 10);if (n >= 0)break;sleep(1);}write(STDOUT_FILENO, buf, n);close(fd);return 0; }

PS:為了示例函數(shù)簡單,我這里沒有考慮異常情況(如open失敗)的處理,而這些是在實際項目中是必不可少的。

非阻塞I/O有一個缺點,如果所有設(shè)備都一直沒有數(shù)據(jù)到達,調(diào)用者則需要反復(fù)查詢,這樣會一直占著cpu不放。因此,在使用非阻塞I/O時,通常不會在一個while循環(huán)中一直不停地查詢(這稱為Tight Loop),而是每延遲等待一會兒來查詢一下,以免做太多無用功,在延遲等待的時候可以調(diào)度其它進程執(zhí)行。

但是,這樣又引入了一個新的問題,可能導(dǎo)致數(shù)據(jù)讀取的不夠及時,就拿我前面的例子來說,我在每次循環(huán)的時候Sleep了一秒。如果剛開始Sleep的時候數(shù)據(jù)可用,但此時卻無法立即響應(yīng),需要到Sleep結(jié)束后鐘才能輸出結(jié)果。

要解圓滿解決這個問題,則需要用到select函數(shù),它可以阻塞地同時監(jiān)視多個設(shè)備,還可以設(shè)定阻塞等待的超時時間,由于select多見于socket編程場景,這里不大好舉例,后續(xù)如果會介紹socket編程的時候再詳細介紹它,要了解它的工作原理可以看一下這篇文章select,多路同步I/O模型。



來自為知筆記(Wiz)

轉(zhuǎn)載于:https://www.cnblogs.com/linzhenjie/p/5485628.html

總結(jié)

以上是生活随笔為你收集整理的Linux高级编程--05.文件读写的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。