第三章 文件I/O

文件描述符

所有打開(kāi)的文件都通過(guò)文件描述符引用。操作(讀寫(xiě))該文件描述符就相當(dāng)于操作該文件宪拥。
文件描述符是一個(gè)非負(fù)的整數(shù)。

同時(shí)文件描述符0,1,2都已經(jīng)對(duì)應(yīng)標(biāo)準(zhǔn)輸出(輸出在終端上),標(biāo)準(zhǔn)輸入(從標(biāo)準(zhǔn)終端輸入)稍算,標(biāo)準(zhǔn)錯(cuò)誤。
對(duì)應(yīng)STDIN_FILENO,STDOUT_FILENO,STDERR_FILENO役拴。
這三個(gè)常量定義在<unistd.h>中糊探。

open和openat

#include <fcntl.h>
int open(const char * path ,int flag, mode_t =NULL)
int openat(int fd,const char * path ,int flag, mode_t =NULL)

兩者的主要區(qū)別是,open只能相對(duì)于程序運(yùn)行的目錄河闰,而openat可以使相對(duì)于fd指定的目錄進(jìn)行打開(kāi)操作科平,同時(shí)fd的特殊值AT_FDCWD指的是當(dāng)前目錄。
同時(shí)可以避免TOCTTOU,意思是如果一個(gè)操作需要兩個(gè)文件操作才能完成姜性,那么中間可能cpu調(diào)度的原因瞪慧,第一個(gè)文件操作已經(jīng)被更改,從而后一個(gè)操作也會(huì)不正確部念∑茫可以用來(lái)獲取特殊權(quán)限。

flag

這個(gè)參數(shù)主要指定了打開(kāi)模式:
一下五個(gè)只能出現(xiàn)一個(gè):

  1. O_RDONLY
    只讀打開(kāi)儡炼,0
  2. O_WDONLY
    只寫(xiě)打開(kāi)妓湘,1
  3. O_RDWE
    讀寫(xiě)打開(kāi),2
  4. O_EXEC
    只 執(zhí)行打開(kāi)乌询。
  5. SEARCH
    只搜索打開(kāi)榜贴,用于目錄

一下這些常量是可選的使用|運(yùn)算與上面的結(jié)合。

  1. O_APPEND
    每次寫(xiě)入到尾端
  2. O_CLOEXEC
    當(dāng)調(diào)用exec()函數(shù)成功后妹田,文件描述符會(huì)自動(dòng)關(guān)閉
  3. O_CREAT
    如果打開(kāi)的文檔不存在唬党,就自動(dòng)創(chuàng)建鹃共,同時(shí)需要指定mode_t參數(shù)
  4. O_DICECTORY
    如果打開(kāi)的不是目錄jiubaocuo
  5. O_EXCL
    如果同時(shí)指定 O_CREATO_EXCL,當(dāng)文件存在的時(shí)候就出錯(cuò)初嘹。
  6. O_NOCTTY
  7. O_NOFOLLOW
    如果打開(kāi)的是一個(gè)連接符號(hào)及汉,就出錯(cuò)
  8. O_NONBLOCK
    非阻塞打開(kāi),如果沒(méi)讀到數(shù)據(jù)就出錯(cuò)返回屯烦。
  9. O_SYNC
    寫(xiě)入數(shù)據(jù)是坷随,需要等到數(shù)據(jù)真正寫(xiě)入到硬盤(pán)時(shí)才返回,包括文件屬性的更新驻龟。
    ext4下温眉,同步寫(xiě)和延時(shí)寫(xiě)差距不大?hfs下差距很大翁狐。和系統(tǒng)有關(guān)类溢?
  10. O_DSYNC
    寫(xiě)入數(shù)據(jù)是,需要等到數(shù)據(jù)真正寫(xiě)入到硬盤(pán)時(shí)才返回露懒,如果不影響讀取剛寫(xiě)入的數(shù)據(jù)闯冷,則不需要等待文件屬性更新。
  11. O_RSYNC
    讀操作會(huì)等待所有對(duì)該文件的寫(xiě)操作完成以后才執(zhí)行懈词。
  12. O_DICECT
    看不懂

creat()

#include <fnctl.h>
int creat(const char* path,mode_t mode)
//出錯(cuò)返回-1

缺點(diǎn)是都是以只寫(xiě)操作打開(kāi)該文檔蛇耀,所以如果要讀,需要關(guān)閉該文件描述符重新打開(kāi)坎弯。
一般使用open(path,O_RDWR|O_CREAT,mode)代替纺涤。

close()

#include <unistd.h>
int close(int fd);
//成功返回0 ,出錯(cuò)返回-1

關(guān)閉文檔抠忘,釋放所有記錄鎖撩炊。
進(jìn)程關(guān)閉以后,會(huì)關(guān)閉所有該進(jìn)程所打開(kāi)的文件崎脉。

lseek()

#include <unistd.h>
off_t lseek(int fd,off_t offset,int whence);
//出錯(cuò)返回-1拧咳,否則返回新的穩(wěn)健偏移量

whence

偏移的起點(diǎn)

  1. SEEK_SET
    將文件的偏移量設(shè)置為距文件開(kāi)頭offset個(gè)字節(jié),也就是說(shuō)囚灼,起點(diǎn)是開(kāi)頭
  2. SEEK_CUR
    偏移起點(diǎn)文當(dāng)前起點(diǎn)呛踊,offset可正可負(fù)
  3. SEEK_END
    偏移起點(diǎn)為文件的總長(zhǎng)度。也就是說(shuō)起點(diǎn)在末尾啦撮。

如果將文件描述符對(duì)一個(gè)管道FIFO或者套接字使用,那么返回-1汪厨,并且赃春,errno為ESPIPE
因?yàn)檫@三個(gè)都是流式的,只能讀寫(xiě)劫乱,不能設(shè)置偏移量织中。

如果將偏移量定位在結(jié)尾之后開(kāi)始寫(xiě)入數(shù)據(jù)锥涕,那么中間的空洞被讀為0。

read()

#include <unistd.h>
ssize_t read(int fd,void *buf,size_t n);
//成功返回讀到的字節(jié)數(shù)狭吼,到文件尾返回0层坠,出錯(cuò)返回-1

ssize_t是一個(gè)帶符號(hào)的整數(shù)。而size_t是一個(gè)不帶符號(hào)的整數(shù)刁笙。

讀到的字節(jié)小于設(shè)置的字節(jié)數(shù)原因:

  1. 讀到末尾
    本次返回讀到的數(shù)據(jù)破花,下一次返回0
  2. 從終端設(shè)備讀,每次只能一行
  3. 從網(wǎng)絡(luò)中讀是疲吸,網(wǎng)絡(luò)的緩存機(jī)制可能造成
  4. 管道和FIFO中時(shí)座每,管道中的字節(jié)數(shù)少于所需數(shù)量
  5. 信號(hào)中斷前已經(jīng)讀到數(shù)據(jù)

讀文件從文件當(dāng)前偏移量開(kāi)始,成功返回之前摘悴,改變偏移量峭梳。

write()

#include <unistd.h>
ssize_t write(int fd,const buf*,size_t n);
//成功返回寫(xiě)入的字節(jié)數(shù)蹂喻,錯(cuò)誤返回-1

從偏移量位置開(kāi)始寫(xiě)葱椭。
如果設(shè)置了O_APPEND則每次寫(xiě)操作之前將文件偏移量設(shè)置在文件的結(jié)尾處。

根據(jù)局部性原理口四,系統(tǒng)會(huì)預(yù)讀比所指定數(shù)量多的數(shù)據(jù)孵运,并假設(shè)它們很快會(huì)被用到。

文件共享

多進(jìn)程間操作同一文件窃祝。

文件描述符標(biāo)志和文件狀態(tài)標(biāo)志

  1. 文件描述符標(biāo)志
    是體現(xiàn)進(jìn)程的文件描述符的狀態(tài)掐松,fork進(jìn)程時(shí),文件描述符被復(fù)制粪小;
    目前只有一種文件描述符:FD_CLOEXEC大磺。指明是否復(fù)制進(jìn)新的進(jìn)程。
  2. 文件狀態(tài)標(biāo)志
    是體現(xiàn)進(jìn)程打開(kāi)文件的一些標(biāo)志探膊,fork時(shí)不會(huì)復(fù)制file 結(jié)構(gòu)杠愧,而是兩個(gè)進(jìn)程文件描述符指向同一個(gè)file(當(dāng)FD的exec標(biāo)志為0時(shí))

內(nèi)和使用三種結(jié)構(gòu)表示打開(kāi)的文件

  1. 內(nèi)核的記錄項(xiàng):文件描述符標(biāo)志,文件表項(xiàng)逞壁,V節(jié)點(diǎn)表項(xiàng)
    每個(gè)進(jìn)程在進(jìn)程表中都有一個(gè)記錄項(xiàng)流济,每個(gè)描述符占一項(xiàng)。
    每一項(xiàng)都有一個(gè)標(biāo)志腌闯,該標(biāo)志表示該文件描述符的特性绳瘟,可以使用fnctl()獲取和改變。
    一個(gè)指向文件表項(xiàng)的指針(指向內(nèi)核中)
  2. 內(nèi)核的文件表
    內(nèi)核記錄文件的狀態(tài)標(biāo)志姿骏,文件表項(xiàng)中記錄著文件狀態(tài)標(biāo)志:阻塞糖声,同步的方式。在該進(jìn)程中打開(kāi)的文件的偏移量(不同進(jìn)程中可以不同)。還有一個(gè)指向V節(jié)點(diǎn)表項(xiàng)的指針蘸泻。
  3. V節(jié)點(diǎn)結(jié)構(gòu)
    V節(jié)點(diǎn)表項(xiàng)是所有進(jìn)程共有一份琉苇,表示文件的信息:長(zhǎng)度,修改時(shí)間等悦施。
    應(yīng)該是存在硬盤(pán)上并扇。
    不同進(jìn)程公用一份。

原子操作的IO

讀寫(xiě)

#include <unistd.h>
ssize_t pread(int fd,void *buf,size_t n,off_t offset);
ssize_t pwrite(int fd,const void *buf,size_t n,off_t offset);
//返回值同以前

但是有用嗎抡诞?offset的值如何確定穷蛹?

復(fù)制文件描述符

#include <unistd.h>
int dup(int fd);
int dup2(int fd,init fd2);
//出錯(cuò)返回-1

第二個(gè)函數(shù),在fd2出復(fù)制fd1,如果fd2處已經(jīng)有一個(gè)文件打開(kāi)了沐绒,那么先關(guān)閉俩莽,在打開(kāi)。是一個(gè)院子操作乔遮。
如果相同扮超,那么步步操作,直接返回蹋肮。

復(fù)制以后出刷,兩個(gè)文件描述符共享一個(gè)文件表項(xiàng)。

緩沖

#incldue <unistd.h>
int sync(void);
int fsync(int fd);
int fdataasync(int fd)
//錯(cuò)誤返回-1
  1. sync
    將所有修改過(guò)的緩存坯辩,排入寫(xiě)隊(duì)列馁龟。也就是實(shí)際寫(xiě)入硬盤(pán),但是不等待寫(xiě)入結(jié)束漆魔。
    對(duì)所有文件
    系統(tǒng)周期性執(zhí)行該函數(shù)坷檩。
  2. fsync
    對(duì)指定fd,將修改過(guò)的緩存寫(xiě)入硬盤(pán)改抡,并且修改文件屬性矢炼,結(jié)束后返回
  3. fdatasync
    對(duì)指定fd,將修改過(guò)的緩存寫(xiě)入硬盤(pán)阿纤,結(jié)束后返回句灌,可以不用等待修改文件屬性結(jié)束。

fcntl()

#include <fcntl.h>
int fcntl(int fd, int cmd,...)

第三個(gè)參數(shù)是一個(gè)整數(shù)(在get時(shí)欠拾,不需要該參數(shù)胰锌,設(shè)為0),或是一個(gè)指針
功能如下:

  1. 復(fù)制文件描述符cmd = F_DUPFD 或 F_DUPFD_CLOEXEC
    cmd = F_DUPFD返回未用最小的整數(shù)作為新的描述符返回藐窄,但是該文件描述符有自己獨(dú)立的文件描述符標(biāo)志资昧,同時(shí)清除了O_CLOEXEC標(biāo)志。而dup()打開(kāi)的是共享的荆忍。
    cmd = F_DUPFD_CLOEXECdup2`榛搔,需要第三個(gè)參數(shù)
  2. 設(shè)置獲取文件描述符狀態(tài)cmd = F_GETFD 和 F_SETFD
    目前可設(shè)置和獲取的只有一種诺凡,是否在新的線程中復(fù)制一份。
    set時(shí)需要第三個(gè)參數(shù)践惑。0不關(guān)閉,1關(guān)閉嘶卧。
  3. 設(shè)置獲取文件狀態(tài)標(biāo)志cmd = F_GETFL 和 F_SETFL
    指的是尔觉,讀寫(xiě),阻塞芥吟,寫(xiě)模式(append)侦铜,同步讀寫(xiě).
    也就是打開(kāi)open的參數(shù)。
    在獲取的時(shí)候钟鸵,由于讀寫(xiě)的五中模式互斥钉稍,所以需要使用一個(gè)屏蔽字O_ACCMODE與運(yùn)算,取得訪問(wèn)方式位棺耍,然后挨個(gè)比較
int val = fcntl(fd,F_GETFL,0)贡未;
switch (val & O_ACCMODE)
  case O_RDONLY:
  case .....

而其余可選的狀態(tài)標(biāo)志,不需要蒙袍。直接進(jìn)行與運(yùn)算

if (val & O_APPEN)
{
}

但是設(shè)置的時(shí)候只能是堵塞模式俊卤,緩存模式。設(shè)置的時(shí)候需要先獲取害幅,然后進(jìn)行|=然后再設(shè)置消恍。不然會(huì)清除之前的設(shè)置。

  1. 設(shè)置獲取異步IO cmd = F_GETOWN 和 F_SETOWN
  2. 獲取設(shè)置記錄所 cmd = F_GETLK F_SETLK F_SETLKW

/dev/fd/n

打開(kāi)文件以现,等于復(fù)制文教描述符狠怨。

int fd=open("/dev/fd/1",O_RDWR);

雖然設(shè)置了讀寫(xiě),但是只能使用之前打開(kāi)的模式邑遏,比如之前是寫(xiě)模式佣赖,那么使用這種方式打開(kāi)也不能讀。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末无宿,一起剝皮案震驚了整個(gè)濱河市茵汰,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌孽鸡,老刑警劉巖蹂午,帶你破解...
    沈念sama閱讀 222,183評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異彬碱,居然都是意外死亡豆胸,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)巷疼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)晚胡,“玉大人,你說(shuō)我怎么就攤上這事」琅蹋” “怎么了瓷患?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,766評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)遣妥。 經(jīng)常有香客問(wèn)我擅编,道長(zhǎng),這世上最難降的妖魔是什么箫踩? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,854評(píng)論 1 299
  • 正文 為了忘掉前任爱态,我火速辦了婚禮,結(jié)果婚禮上境钟,老公的妹妹穿的比我還像新娘锦担。我一直安慰自己,他們只是感情好慨削,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,871評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布洞渔。 她就那樣靜靜地躺著,像睡著了一般理盆。 火紅的嫁衣襯著肌膚如雪痘煤。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,457評(píng)論 1 311
  • 那天猿规,我揣著相機(jī)與錄音衷快,去河邊找鬼。 笑死姨俩,一個(gè)胖子當(dāng)著我的面吹牛蘸拔,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播环葵,決...
    沈念sama閱讀 40,999評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼调窍,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了张遭?” 一聲冷哼從身側(cè)響起邓萨,我...
    開(kāi)封第一講書(shū)人閱讀 39,914評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎菊卷,沒(méi)想到半個(gè)月后缔恳,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,465評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡洁闰,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,543評(píng)論 3 342
  • 正文 我和宋清朗相戀三年歉甚,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片扑眉。...
    茶點(diǎn)故事閱讀 40,675評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡纸泄,死狀恐怖赖钞,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情聘裁,我是刑警寧澤雪营,帶...
    沈念sama閱讀 36,354評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站咧虎,受9級(jí)特大地震影響卓缰,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜砰诵,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,029評(píng)論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望捌显。 院中可真熱鬧茁彭,春花似錦、人聲如沸扶歪。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,514評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)善镰。三九已至妹萨,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間炫欺,已是汗流浹背乎完。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,616評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留品洛,地道東北人树姨。 一個(gè)月前我還...
    沈念sama閱讀 49,091評(píng)論 3 378
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像桥状,于是被迫代替她去往敵國(guó)和親帽揪。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,685評(píng)論 2 360

推薦閱讀更多精彩內(nèi)容

  • apue 第三章 文件I/O 文件描述符 對(duì)于內(nèi)核辅斟,所有打開(kāi)的文件都通過(guò)文件描述符引用 STDIN_FILEOUT...
    buildbody_coder閱讀 380評(píng)論 0 0
  • 文件描述符 非負(fù)整數(shù)谅年,變化范圍(0~OPEN_MAX-1粤蝎,或許是63?) 取得描述符 #include<fcntl...
    WhiteBlue閱讀 436評(píng)論 0 0
  • 1.文件描述符 所有執(zhí)行I/O操作的系統(tǒng)調(diào)用都以文件描述符(一個(gè)非負(fù)整數(shù))來(lái)指代打開(kāi)的文件。文件描述符用以表示所有...
    666真666閱讀 1,107評(píng)論 0 2
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)樱调,斷路器,智...
    卡卡羅2017閱讀 134,711評(píng)論 18 139
  • linux資料總章2.1 1.0寫(xiě)的不好抱歉 但是2.0已經(jīng)改了很多 但是錯(cuò)誤還是無(wú)法避免 以后資料會(huì)慢慢更新 大...
    數(shù)據(jù)革命閱讀 12,175評(píng)論 2 33