今天我們總結(jié)一下,linux中常用文件I/O操作。
目前創(chuàng)新互聯(lián)已為上1000+的企業(yè)提供了網(wǎng)站建設(shè)、域名、虛擬空間、網(wǎng)站托管、服務(wù)器租用、企業(yè)網(wǎng)站設(shè)計、南部網(wǎng)站維護(hù)等服務(wù),公司將堅持客戶導(dǎo)向、應(yīng)用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長,共同發(fā)展。首先讓我們看一下,什么是文件I/O:
所謂文件I/O就是:對于I/O就是input/output,輸入/輸出。文件IO的意思就是讀寫文件。
1、linux給我們留的常用文件I/O接口。
1、open close write read lseek
2、文件操作的一般步驟:
1、在linux中要操作一個文件,一般是先open打開一個文件,得到文件描述符,然后對文件進(jìn)行讀寫操作(或其他操作),最后是close關(guān)閉文件即可。
2、強(qiáng)調(diào)一點:我們對文件進(jìn)行操作時,一定要先打開文件,打開成功之后才能操作,如果打開失敗,就不用進(jìn)行后邊的操作了,最后讀寫完成后,一定要關(guān)閉文件,否則會造成文件損壞。
3、文件平時是存放在塊設(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)文件)。
4、打開文件以后,以后對這個文件的讀寫操作,都是針對內(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)文件。
5、為什么這么設(shè)計,不直接對塊設(shè)備直接操作。
塊設(shè)備本身讀寫非常不靈活,是按塊讀寫的,而內(nèi)存是按字節(jié)單位操作的,而且可以隨機(jī)操作,很靈活。
3、重要概念:
文件描述符:
1、對于內(nèi)核而言,所有打開文件都由文件描述符引用。文件描述符是一個非負(fù)整數(shù)。當(dāng)打開一個現(xiàn)存文件或者創(chuàng)建一個新文件時,內(nèi)核向進(jìn)程返回一個文件描述符。當(dāng)讀寫一個文件時,用open和creat返回的文件描述符標(biāo)識該文件,將其作為參數(shù)傳遞給read和write。
按照慣例,UNIX shell使用文件描述符0與進(jìn)程的標(biāo)準(zhǔn)輸入相結(jié)合,文件描述符1與標(biāo)準(zhǔn)輸出相結(jié)合,文件描述符2與標(biāo)準(zhǔn)錯誤輸出相結(jié)合。STDIN_FILENO、STDOUT_FILENO、STDERR_FILENO這幾個宏代替了0、1、2這幾個魔數(shù)。
2、文件描述符,這個數(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)文件,只需要用這個文件描述符區(qū)分。
3、文件描述符的作用域就是當(dāng)前進(jìn)程,出了這個進(jìn)程文件描述符就沒有意義了。
open函數(shù)打開文件,打開成功返回一個文件描述符,打開失敗,返回-1。
補(bǔ)充:這里我們補(bǔ)充一點,
1、學(xué)習(xí)linux過程中注意學(xué)會使用man手冊,查詢幫助文檔。
2、man 1 xx查linux shell命令,man 2 xxx查API, man 3 xxx查庫函數(shù)
4、常用文件I/O操作的使用:
1、open函數(shù)(打開文件操作)
需要用到的頭文件 #include<sys/types.h> #include<sys/stat.h> #include<fcntl.h> 函數(shù)原型: int open(const char *pathname, int flags); int open(const char *pathname, int flags, mode_t mode); 返回值:若成功返回文件描述符,若出錯返回 -1
對于open函數(shù)而言,僅當(dāng)創(chuàng)建新文件時才使用第三個參數(shù)。namepath是要打開或創(chuàng)建的文件的名字。oflag參數(shù)可以用來說明函數(shù)的多個選項。用下列一個或者多個常數(shù)進(jìn)行或運算構(gòu)成oflag參數(shù)(這些參數(shù)定義在<fcntl.h>頭文件中):
open函數(shù)flags參數(shù)詳解:
讀寫權(quán)限:O_RDONLY O_WRONLY O_RDWR
O_RDONLY 只讀打開
O_WRONLY 只寫打開
O_RDWR 可讀可寫打開
當(dāng)我們附帶了權(quán)限后,打開的文件就只能按照這種權(quán)限來操作。以上這三個常數(shù)中應(yīng)當(dāng)只指定一 個。下列常數(shù)是可選擇的:
O_CREAT 若文件不存在則創(chuàng)建它。使用此選項時,需要同時說明第三個參數(shù)mode,用其說明該新文件的存取許可權(quán)限。
O_EXCL 如果同時指定了OCREAT,而文件已經(jīng)存在,則出錯。這可測試一個文件是
否存在,如果不存在則創(chuàng)建此文件成為一個原子操作。3 . 11節(jié)將較詳細(xì)地說明原子操作。
O_APPEND 每次寫時都加到文件的尾端。
O_TRUNC 屬性去打開文件時,如果這個文件中本來是有內(nèi)容的,而且為只讀或只寫成功打開,則將其長度截短為0。
重點:
一: 打開存在并有內(nèi)容的文件時:O_APPEND、O_TRUNC
(1)思考一個問題:當(dāng)我們打開一個已經(jīng)存在并且內(nèi)部有內(nèi)容的文件時會怎么樣?
可能結(jié)果1:新內(nèi)容會替代原來的內(nèi)容(原來的內(nèi)容就不見了,丟了)
可能結(jié)果2:新內(nèi)容添加在前面,原來的內(nèi)容繼續(xù)在后面
可能結(jié)果3:新內(nèi)容附加在后面,原來的內(nèi)容還在前面
可能結(jié)果4:不讀不寫的時候,原來的文件中的內(nèi)容保持不變
(2)O_TRUNC屬性去打開文件時,如果這個文件中本來是有內(nèi)容的,則原來的內(nèi)容會被丟棄。這就對應(yīng)上面的結(jié)果1
(3)O_APPEND屬性去打開文件時,如果這個文件中本來是有內(nèi)容的,則新寫入的內(nèi)容會接續(xù)到原來內(nèi)容的后面,對應(yīng)結(jié)果3
(4)默認(rèn)不使用O_APPEND和O_TRUNC屬性時就是結(jié)果4
(5)如果O_APPEND和O_TRUNC同時出現(xiàn)會會清空文件。
二:打開不存在的文件時:O_CREAT、O_EXCL
(1)思考:當(dāng)我們?nèi)ゴ蜷_一個并不存在的文件時會怎樣?當(dāng)我們open打開一個文件時如果這個文件名不存在則會打開文件錯誤。
(2)vi或者windows下的notepad++,都可以直接打開一個尚未存在的文件。
(3)open的flag O_CREAT就是為了應(yīng)對這種打開一個并不存在的文件的。O_CREAT就表示我們當(dāng)前打開的文件并不存在,我們是要去創(chuàng)建并且打開它。
(4)思考:當(dāng)我們open使用了O_CREAT,但是文件已經(jīng)存在的情況下會怎樣?經(jīng)過實驗驗證發(fā)現(xiàn)結(jié)果是報錯。
(5)結(jié)論:open中加入O_CREAT后,不管原來這個文件存在與否都能打開成功,如果原來這個文件不存在則創(chuàng)建一個空的新文件,如果原來這個文件存在則會重新創(chuàng)建這個文件,原來的內(nèi)容會被消除掉(有點類似于先刪除原來的文件再創(chuàng)建一個新的)
(6)這樣可能帶來一個問題?我們本來是想去創(chuàng)建一個新文件的,但是把文件名搞錯了弄成了一個老文件名,結(jié)果老文件就被意外修改了。我們希望的效果是:如果我CREAT要創(chuàng)建的是一個已經(jīng)存在的名字的文件,則給我報錯,不要去創(chuàng)建。
(7)這個效果就要靠O_EXCL標(biāo)志和O_CREAT標(biāo)志來結(jié)合使用。當(dāng)這連個標(biāo)志一起的時候,則沒有文件時創(chuàng)建文件,有這個文件時會報錯提醒我們。
(8)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_NOCTTY 如果pathname指的是終端設(shè)備,則不將此設(shè)備分配作為此進(jìn)程的控制終端。9.6節(jié)將說明控制終端。
O_NONBLOCK 如果pathname指的是一個FIFO、一個塊特殊文件或一個字符特殊文件,則此選擇項為此文件的本次打開操作和后續(xù)的I/O操作設(shè)置非阻塞方式。(只用于設(shè)備文件,而不用于普通文件。)
(1)阻塞與非阻塞。如果一個函數(shù)是阻塞式的,則我們調(diào)用這個函數(shù)時當(dāng)前進(jìn)程有可能被卡?。ㄗ枞?,實質(zhì)是這個函數(shù)內(nèi)部要完成的事情條件不具備,當(dāng)前沒法做,要等待條件成熟),函數(shù)被阻塞住了就不能立刻返回;如果一個函數(shù)是非阻塞式的那么我們調(diào)用這個函數(shù)后一定會立即返回,但是函數(shù)有沒有完成任務(wù)不一定。
(2)阻塞和非阻塞是兩種不同的設(shè)計思路,并沒有好壞??偟膩碚f,阻塞式的結(jié)果有保障但是時間沒保障;非阻塞式的時間有保障但是結(jié)果沒保障。
(3)操作系統(tǒng)提供的API和由API封裝而成的庫函數(shù),有很多本身就是被設(shè)計為阻塞式或者非阻塞式的,所以我們應(yīng)用程度調(diào)用這些函數(shù)的時候心里得非常清楚。
(4)我們打開一個文件默認(rèn)就是阻塞式的,如果你希望以非阻塞的方式打開文件,則flag中要加O_NONBLOCK標(biāo)志。
O_SYNC 使每次write都等到物理I/O操作完成
(1)write阻塞等待底層完成寫入才返回到應(yīng)用層。
(2)無O_SYNC時write只是將內(nèi)容寫入底層緩沖區(qū)即可返回,然后底層(操作系統(tǒng)中負(fù)責(zé)實現(xiàn)open、write這些操作的那些代碼,也包含OS中讀寫硬盤等底層硬件的代碼)在合適的時候會將buf中的內(nèi)容一次性的同步到硬盤中。這種設(shè)計是為了提升硬件操作的性能和銷量,提升硬件壽命;但是有時候我們希望硬件不好等待,直接將我們的內(nèi)容寫入硬盤中,這時候就可以用O_SYNC標(biāo)志。
2、creat函數(shù)(也可用creat函數(shù)創(chuàng)建一個新文件)
需要用到的頭文件 #include<sys/types.h> #include<sys/stat.h> #include<fcutl.h> 函數(shù)原型: int creat(const char *pathname, mode_t mode); 返回:若成功為只寫打開的文件描述符,若出錯為-1
此函數(shù)等效于 open(pathname,O_WRONLY|O_CRAT|O_TRUNC,mode);
3、read 函數(shù)(用read函數(shù)從打開的文件中讀取數(shù)據(jù))
需要的頭文件: #include<unistd.h> 函數(shù)原型: ssize_t read(int filedes,void *buffer,size_t nbytes); 返回值:讀取到字節(jié)數(shù),若已到文件尾0,則返回-1如果read成功,則返回讀取到字節(jié)數(shù)。如已到文件結(jié)尾返回0;
有多種情況可使實際讀到的字節(jié)數(shù)少于要求讀字節(jié)數(shù):
1、讀取普通文件時,在讀到要求字節(jié)數(shù)之前已經(jīng)到達(dá)了文件結(jié)尾。例如,若在到達(dá)文件尾端之前還有30個字節(jié),而要求讀100個字節(jié),則read返回30,下一次調(diào)用read時,它將返回0(文件尾端)。
2、當(dāng)從終端設(shè)備讀時,通常一次最多讀一行
3、當(dāng)從網(wǎng)絡(luò)讀時,網(wǎng)絡(luò)中緩存機(jī)構(gòu)可能造成返回值小于所要求讀的字節(jié)數(shù)。
4、某些面向記錄的設(shè)備,例如磁帶,一次最多返回一個記錄。
4、write函數(shù)(用write函數(shù)向打開的文件寫數(shù)據(jù))
需要用到的頭文件 #include<unistd.h> 函數(shù)原型: ssize_t write(int filedes,const void buffer,size_t nbytes); 返回值:若成功返回已寫字節(jié)數(shù),若出錯返回-1 其返回值通常與參數(shù)nbyte的值不同,否則表示出錯。write出錯的一個常見原因是:磁盤已寫滿,或者超過了對一個給定進(jìn)程的文件長度限制。
寫入用write系統(tǒng)調(diào)用,write的原型和理解方法和read相似
5、close函數(shù)(可以用close函數(shù)關(guān)閉一個打開是文件)
需要用到的頭文件: #include<unistd.h> 函數(shù)原型: int close(int filedes); 返回值:成功返回0,若出錯返回-1
當(dāng)一個進(jìn)程終止時,它所有的打開的文件都是由內(nèi)核自動關(guān)閉。
6、lseek函數(shù)
每個打開文件都有一個與其相關(guān)聯(lián)的“當(dāng)前文件位移量”。它是一個非負(fù)整數(shù),用以度量從文件開始處計算的字節(jié)數(shù)。
需要用到的頭文件 #include<sys/types.h> #include<unistd.h> 函數(shù)原型: off_t lseek(int filedes,off_t offset,int whence); 返回值:若成功為新的文件的位移,若出錯位-1
對參數(shù)offset 的解釋與參數(shù)whence的值有關(guān)。
若whence是SEEK_SET,則將該文件的位移量設(shè)置為距文件開始處offset 個字節(jié)。
若whence是SEEK_CUR,則將該文件的位移量設(shè)置為其當(dāng)前值加offset, offset可為正或負(fù)。
若whence是SEEK_END,則將該文件的位移量設(shè)置為文件長度加offset, offset可為正或負(fù)。*******************************************************************************************
重要概念:
(1)文件指針:當(dāng)我們要對一個文件進(jìn)行讀寫時,一定需要先打開這個文件,所以我們讀寫的所有文件都是動態(tài)文件。動態(tài)文件在內(nèi)存中的形態(tài)就是文件流的形式。
(2)文件流很長,里面有很多個字節(jié)。那我們當(dāng)前正在操作的是哪個位置?GUI模式下的軟件用光標(biāo)來標(biāo)識這個當(dāng)前正在操作的位置,這是給人看的。
(3)在動態(tài)文件中,我們會通過文件指針來表征這個正在操作的位置。所謂文件指針,就是我們文件管理表這個結(jié)構(gòu)體里面的一個指針。所以文件指針其實是vnode中的一個元素。這個指針表示當(dāng)前我們正在操作文件流的哪個位置。這個指針不能被直接訪問,linux系統(tǒng)用lseek函數(shù)來訪問這個文件指針。
(4)當(dāng)我們打開一個空文件時,默認(rèn)情況下文件指針指向文件流的開始。所以這時候去write時寫入就是從文件開頭開始的。write和read函數(shù)本身自帶移動文件指針的功能,所以當(dāng)我write了n個字節(jié)后,文件指針會自動向后移動n位。如果需要人為的隨意更改文件指針,那就只能通過lseek函數(shù)了
(5)read和write函數(shù)都是從當(dāng)前文件指針處開始操作的,所以當(dāng)我們用lseek顯式的將文件指針移動后,那么再去read/write時就是從移動過后的位置開始的。
(6)回顧前面一節(jié)中我們從空文件,先write寫了12字節(jié),然后read時是空的(但是此時我們打開文件后發(fā)現(xiàn)12字節(jié)確實寫進(jìn)來了)。
lseek函數(shù)幾個用途:
1、用lseek計算文件長度
(1)linux中并沒有一個函數(shù)可以直接返回一個文件的長度。但是我們做項目時經(jīng)常會需要知道一個文件的長度,怎么辦?自己利用lseek來寫一個函數(shù)得到文件長度即可。
#include<stdio.h> #include<unistd.h> #include<sys/types.h> #include<sys/stat.h> #include<fcntl.h> #include<stdlib.h> #include<string.h> #include<errno.h> typedef int file_t; #define MAXLENG 1024 int main(int argc,char *argv[]) { file_t fd = -1; ssize_t ret = -1; if(2 != argc) { fprintf(stdout,"usage: %s filename \n",argv[0]); _exit(-1); } char buffer[MAXLENG] = {0}; fd = open(argv[1],O_RDONLY); //文件打開成功,文件指針指向文件開頭 if(-1 == fd) { perror("open file error:"); _exit(-1); } else { fprintf(stdout,"文件打開成功\n"); ret = lseek(fd,0,SEEK_END); } fprintf(stdout,"文件長度是: %d\n",ret); return 0; }
2、用lseek構(gòu)建空洞文件
(1)空洞文件就是這個文件中有一段是空的。
(2)普通文件中間是不能有空的,因為我們write時文件指針是依次從前到后去移動的,不可能繞過前面直接到后面。
(3)我們打開一個文件后,用lseek往后跳過一段,再write寫入一段,就會構(gòu)成一個空洞文件。
(4)空洞文件方法對多線程共同操作文件是及其有用的。有時候我們創(chuàng)建一個很大的文件,如果從頭開始依次構(gòu)建時間很長。有一種思路就是將文件分為多段,然后多線程來操作每個線程負(fù)責(zé)其中一段的寫入。
補(bǔ)充:
1、exit、_exit、_Exit退出進(jìn)程
(1)當(dāng)我們程序在前面步驟操作失敗導(dǎo)致后面的操作都沒有可能進(jìn)行下去時,應(yīng)該在前面的錯誤監(jiān)測中結(jié)束整個程序,不應(yīng)該繼續(xù)讓程序運行下去了。
(2)我們?nèi)绾瓮顺龀绦颍?/p>
第一種;在main用return,一般原則是程序正常終止return 0,如果程序異常終止則return -1。
第一種:正式終止進(jìn)程(程序)應(yīng)該使用exit或者_(dá)exit或者_(dá)Exit之一。
2、文件讀寫的一些細(xì)節(jié)
<1> 、errno和perror
(1)errno就是error number,意思就是錯誤號碼。linux系統(tǒng)中對各種常見錯誤做了個編號,當(dāng)函數(shù)執(zhí)行錯誤時,函數(shù)會返回一個特定的errno編號來告訴我們這個函數(shù)到底哪里錯了。
(2)errno是由OS來維護(hù)的一個全局變量,任何OS內(nèi)部函數(shù)都可以通過設(shè)置errno來告訴上層調(diào)用者究竟剛才發(fā)生了一個什么錯誤。
(3)errno本身實質(zhì)是一個int類型的數(shù)字,每個數(shù)字編號對應(yīng)一種錯誤。當(dāng)我們只看errno時只能得到一個錯誤編號數(shù)字(譬如-37),不適應(yīng)于人看。
(4)linux系統(tǒng)提供了一個函數(shù)perror(意思print error),perror函數(shù)內(nèi)部會讀取errno并且將這個不好認(rèn)的數(shù)字直接給轉(zhuǎn)成對應(yīng)的錯誤信息字符串,然后print打印出來。
<2>、read和write的count
(1)count和返回值的關(guān)系。count參數(shù)表示我們想要寫或者讀的字節(jié)數(shù),返回值表示實際完成的要寫或者讀的字節(jié)數(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),然后通過多次讀取來實現(xiàn)全部讀完。
<3>、文件IO效率和標(biāo)準(zhǔn)IO
(1)文件IO就指的是我們當(dāng)前在講的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ù)其實是由文件IO封裝而來的(fopen內(nèi)部其實調(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ù)硬盤的特性來選擇好的實際去最終寫入硬盤中)。
3、linux系統(tǒng)如何管理文件
<1>、硬盤中的靜態(tài)文件和inode(i節(jié)點)
(1)文件平時都在存放在硬盤中的,硬盤中存儲的文件以一種固定的形式存放的,我們叫靜 態(tài)文件。
(2)一塊硬盤中可以分為兩大區(qū)域:一個是硬盤內(nèi)容管理表項,另一個是真正存儲內(nèi)容的區(qū)域。操作系統(tǒng)訪問硬盤時是先去讀取硬盤內(nèi)容管理表,從中找到我們要訪問的那個文件的扇區(qū)級別的信息,然后再用這個信息去查詢真正存儲內(nèi)容的區(qū)域,最后得到我們要的文件。
(3)操作系統(tǒng)最初拿到的信息是文件名,最終得到的是文件內(nèi)容。第一步就是去查詢硬盤內(nèi)容管理表,這個管理表中以文件為單位記錄了各個文件的各種信息,每一個文件有一個信息列表(我們叫inode,i節(jié)點,其實質(zhì)是一個結(jié)構(gòu)體,這個結(jié)構(gòu)體有很多元素,每個元素記錄了這個文件的一些信息,其中就包括文件名、文件在硬盤上對應(yīng)的扇區(qū)號、塊號那些東西·····)
強(qiáng)調(diào):硬盤管理的時候是以文件為單位的,每個文件一個inode,每個inode有一個數(shù)字編號,對應(yīng)一個結(jié)構(gòu)體,結(jié)構(gòu)體中記錄了各種信息。
(4)聯(lián)系平時實踐,大家格式化硬盤(U盤)時發(fā)現(xiàn)有:快速格式化和底層格式化。快速格式化非???,格式化一個32GB的U盤只要1秒鐘,普通格式化格式化速度慢。這兩個的差異?其實快速格式化就是只刪除了U盤中的硬盤內(nèi)容管理表(其實就是inode),真正存儲的內(nèi)容沒有動。這種格式化的內(nèi)容是有可能被找回的。
<2>、內(nèi)存中被打開的文件和vnode(v節(jié)點)
(1)一個程序的運行就是一個進(jìn)程,我們在程序中打開的文件就屬于某個進(jìn)程。每個進(jìn)程都有一個數(shù)據(jù)結(jié)構(gòu)用來記錄這個進(jìn)程的所有信息(叫進(jìn)程信息表),表中有一個指針會指向一個文件管理表,文件管理表中記錄了當(dāng)前進(jìn)程打開的所有文件及其相關(guān)信息。文件管理表中用來索引各個打開的文件的index就是文件描述符fd,我們最終找到的就是一個已經(jīng)被打開的文件的管理結(jié)構(gòu)體vnode
(2)一個vnode中就記錄了一個被打開的文件的各種信息,而且我們只要知道這個文件的fd,就可以很容易的找到這個文件的vnode進(jìn)而對這個文件進(jìn)行各種操作。
<3>、文件與流的概念
(1)流(stream)對應(yīng)自然界的水流。文件操作中,文件類似是一個大包裹,里面裝了一堆字符,但是文件被讀出/寫入時都只能一個字符一個字符的進(jìn)行,而不能一股腦兒的讀寫,那么一個文件中N多的個字符被挨個一次讀出/寫入時,這些字符就構(gòu)成了一個字符流。
(2)流這個概念是動態(tài)的,不是靜態(tài)的。
(3)編程中提到流這個概念,一般都是IO相關(guān)的。所以經(jīng)常叫IO流。文件操作時就構(gòu)成了一個IO流。
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務(wù)可用性高、性價比高”等特點與優(yōu)勢,專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場景需求。
網(wǎng)頁題目:linuxC編程之常用文件I/O操作-創(chuàng)新互聯(lián)
本文URL:http://aaarwkj.com/article26/ddddjg.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供做網(wǎng)站、電子商務(wù)、ChatGPT、關(guān)鍵詞優(yōu)化、品牌網(wǎng)站建設(shè)、全網(wǎng)營銷推廣
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容