操作系統(tǒng)API:
1、API是一些函數(shù),這些函數(shù)是由linux系統(tǒng)提供支持的,由應(yīng)用層程序來使用,應(yīng)用層程序通過調(diào)用API來調(diào)用操作系統(tǒng)中的各種功能,來干活
文件操作的一般步驟:
1、在linux系統(tǒng)中要操作一個文件,一般是先open打開一個文件,得到一個文件描述符,然后對文件進(jìn)行讀寫操作(或其他操作),最后close關(guān)閉文件即可
2、文件平時是存在塊設(shè)備中的文件系統(tǒng)中的,我們把這種文件叫靜態(tài)文件。當(dāng)我們?nèi)pen打開一個文件時,linux內(nèi)核做的操作包括:內(nèi)核在進(jìn)程中建立了一個打開文件的數(shù)據(jù)結(jié)構(gòu),記錄下我們打開的這個文件;內(nèi)核在內(nèi)存中申請一段內(nèi)存,并且將靜態(tài)文件的內(nèi)容從塊設(shè)備中讀取到內(nèi)存中特定地址管理存放(叫動態(tài)文件)。打開文件后,以后對這個文件的讀寫操作,都是針對內(nèi)存中這一份動態(tài)文件的,而并不是針對靜態(tài)文件的。當(dāng)我們對動態(tài)文件進(jìn)行讀寫后,此時內(nèi)存中的動態(tài)文件和塊設(shè)備中的靜態(tài)文件就不同步了,當(dāng)我們close關(guān)閉動態(tài)文件時,close內(nèi)部內(nèi)核將內(nèi)存中的動態(tài)文件的內(nèi)容去更新(同步)塊設(shè)備中的靜態(tài)文件。
3、為什么要這么設(shè)計(jì)?
以為塊設(shè)備本身有讀寫限制(回憶NnadFlash、SD等塊設(shè)備的讀寫特征),本身對塊設(shè)備進(jìn)行操作非常不靈活。而內(nèi)存可以按字節(jié)為單位來操作,而且可以隨機(jī)操作(內(nèi)存就叫RAM,random),很靈活。所以內(nèi)核設(shè)計(jì)文件操作時就這么設(shè)計(jì)了
文件描述符:
1、文件描述符其實(shí)實(shí)質(zhì)是一個數(shù)字,這個數(shù)字在一個進(jìn)程中表示一個特定的含義,當(dāng)我們open打開一個文件時,操作系統(tǒng)在內(nèi)存中構(gòu)建了一些數(shù)據(jù)結(jié)構(gòu)來表示這個動態(tài)文件,然后返回給應(yīng)用程序一個數(shù)字作為文件描述符,這個數(shù)字就和我們內(nèi)存中維護(hù)這個動態(tài)文件的這些數(shù)據(jù)結(jié)構(gòu)掛鉤綁定上了,以后我們應(yīng)用程序如果要操作這一個動態(tài)文件,只需要用這個文件描述符進(jìn)行區(qū)分。
2、文件描述符的作用域就是當(dāng)前進(jìn)程,出了當(dāng)前進(jìn)程這個文件描述符就沒有意義了
實(shí)時查man手冊
(1)當(dāng)我們寫應(yīng)用程序時,很多API原型都不可能記得,所以要實(shí)時查詢,用man手冊
(2)man 1 xx查linux shell命令,man 2 xxx查API, man 3 xxx查庫函數(shù)
讀取文件內(nèi)容
ssize_t read(int fd, void *buf, size_t count);
fd表示要讀取哪個文件,fd一般由前面的open返回得到
buf是應(yīng)用程序自己提供的一段內(nèi)存緩沖區(qū),用來存儲讀出的內(nèi)容
count是我們要讀取的字節(jié)數(shù)
返回值ssize_t類型是linux內(nèi)核用typedef重定義的一個類型(其實(shí)就是int),返回值表示成功讀取的字節(jié)數(shù)。
exit、_exit、_Exit退出進(jìn)程
(1)當(dāng)我們程序在前面步驟操作失敗導(dǎo)致后面的操作都沒有可能進(jìn)行下去時,應(yīng)該在前面的錯誤監(jiān)測中結(jié)束整個程序,不應(yīng)該繼續(xù)讓程序運(yùn)行下去了。
(2)我們?nèi)绾瓮顺龀绦颍?/p>
第一種;在main用return,一般原則是程序正常終止return 0,如果程序異常終止則return -1。
第一種:正式終止進(jìn)程(程序)應(yīng)該使用exit或者_(dá)exit或者_(dá)Exit之一
open函數(shù)的flag詳解:
讀寫權(quán)限:O_RDONLY O_WRONLY O_RDWR
O_RDONLY就表示以只讀方式打開,
O_WRONLY表示以只寫方式打開,
O_RDWR表示以可讀可寫方式打開
當(dāng)我們附帶了權(quán)限后,打開的文件就只能按照這種權(quán)限來操作
打開存在并有內(nèi)容的文件時:O_APPEND、O_TRUNC
O_APPEND屬性去打開文件時,如果這個文件中本來是有內(nèi)容的,則新寫入的內(nèi)容會接續(xù)到原來內(nèi)容的后面;
O_TRUNC屬性去打開文件時,如果這個文件中本來是有內(nèi)容的,則原來的內(nèi)容會被丟棄
打開不存在的文件時:O_CREAT、O_EXCL
open中加入O_CREAT后,不管原來這個文件存在與否都能打開成功,如果原來這個文件不存在則創(chuàng)建一個空的新文件,如果原來這個文件存在則會重新創(chuàng)建這個文件,原來的內(nèi)容會被消除掉;
O_EXCL標(biāo)志和O_CREAT標(biāo)志結(jié)合使用時,則沒有文件時創(chuàng)建文件,有這個文件時會報(bào)錯提醒我們;
open函數(shù)在使用O_CREAT標(biāo)志去創(chuàng)建文件時,可以使用第三個參數(shù)mode來指定要創(chuàng)建的文件的權(quán)限。mode使用4個數(shù)字來指定權(quán)限的,其中后面三個很重要,對應(yīng)我們要創(chuàng)建的這個文件的權(quán)限標(biāo)志。譬如一般創(chuàng)建一個可讀可寫不可執(zhí)行的文件就用0666
O_NONBLOCK
(1)阻塞與非阻塞。如果一個函數(shù)是阻塞式的,則我們調(diào)用這個函數(shù)時當(dāng)前進(jìn)程有可能被卡住(阻塞住,實(shí)質(zhì)是這個函數(shù)內(nèi)部要完成的事情條件不具備,當(dāng)前沒法做,要等待條件成熟),函數(shù)被阻塞住了就不能立刻返回;如果一個函數(shù)是非阻塞式的那么我們調(diào)用這個函數(shù)后一定會立即返回,但是函數(shù)有沒有完成任務(wù)不一定。
(2)阻塞和非阻塞是兩種不同的設(shè)計(jì)思路,并沒有好壞??偟膩碚f,阻塞式的結(jié)果有保障但是時間沒保障;非阻塞式的時間有保障但是結(jié)果沒保障。
(3)操作系統(tǒng)提供的API和由API封裝而成的庫函數(shù),有很多本身就是被設(shè)計(jì)為阻塞式或者非阻塞式的,所以我們應(yīng)用程度調(diào)用這些函數(shù)的時候心里得非常清楚。
(4)我們打開一個文件默認(rèn)就是阻塞式的,如果你希望以非阻塞的方式打開文件,則flag中要加O_NONBLOCK標(biāo)志。
(5)只用于設(shè)備文件,而不用于普通文件。
errno和perror
(1)errno就是error number,意思就是錯誤號碼。linux系統(tǒng)中對各種常見錯誤做了個編號,當(dāng)函數(shù)執(zhí)行錯誤時,函數(shù)會返回一個特定的errno編號來告訴我們這個函數(shù)到底哪里錯了。
(2)linux系統(tǒng)提供了一個函數(shù)perror(意思print error),perror函數(shù)內(nèi)部會讀取errno并且將這個不好認(rèn)的數(shù)字直接給轉(zhuǎn)成對應(yīng)的錯誤信息字符串,然后print打印出來。
read和write的count
(1)count和返回值的關(guān)系:count參數(shù)表示我們想要寫或者讀的字節(jié)數(shù),返回值表示實(shí)際完成的要寫或者讀的字節(jié)數(shù)。實(shí)現(xiàn)的有可能等于想要讀寫的,也有可能小于(說明沒完成任務(wù))
(2)count再和阻塞非阻塞結(jié)合起來,就會更加復(fù)雜。如果一個函數(shù)是阻塞式的,則我們要讀取30個,結(jié)果暫時只有20個時就會被阻塞住,等待剩余的10個可以讀。
(3)有時候我們寫正式程序時,我們要讀取或者寫入的是一個很龐大的文件(譬如文件有2MB),我們不可能把count設(shè)置為2*1024*1024,而應(yīng)該去把count設(shè)置為一個合適的數(shù)字(譬如2048、4096),然后通過多次讀取來實(shí)現(xiàn)全部讀完。
文件IO效率和標(biāo)準(zhǔn)IO
(1)文件IO就指的是open、close、write、read等API函數(shù)構(gòu)成的一套用來讀寫文件的體系,這套體系可以很好的完成文件讀寫,但是效率并不是最高的。
(2)應(yīng)用層C語言庫函數(shù)提供了一些用來做文件讀寫的函數(shù)列表,叫標(biāo)準(zhǔn)IO。標(biāo)準(zhǔn)IO由一系列的C庫函數(shù)構(gòu)成(fopen、fclose、fwrite、fread),這些標(biāo)準(zhǔn)IO函數(shù)其實(shí)是由文件IO封裝而來的(fopen內(nèi)部其實(shí)調(diào)用的還是open,fwrite內(nèi)部還是通過write來完成文件寫入的)。標(biāo)準(zhǔn)IO加了封裝之后主要是為了在應(yīng)用層添加一個緩沖機(jī)制,這樣我們通過fwrite寫入的內(nèi)容不是直接進(jìn)入內(nèi)核中的buf,而是先進(jìn)入應(yīng)用層標(biāo)準(zhǔn)IO庫自己維護(hù)的buf中,然后標(biāo)準(zhǔn)IO庫自己根據(jù)操作系統(tǒng)單次write的最佳count來選擇好的時機(jī)來完成write到內(nèi)核中的buf(內(nèi)核中的buf再根據(jù)硬盤的特性來選擇好的實(shí)際去最終寫入硬盤中)。