Linux基礎(chǔ) ——’文件編程‘是怎么回事?
LINUX基礎(chǔ) ——文件編程篇
「Linux 一切皆是文件 文件系統(tǒng)(文件夾/文件)硬件設(shè)備 ,管道,數(shù)據(jù)庫,Socket等」
一、文件編程概述:
1.應(yīng)用中比如:「賬單,游戲進(jìn)度,配置文件等。」2.用代碼操作文件:「實(shí)現(xiàn)文件創(chuàng)建,打開,編輯等自動(dòng)化執(zhí)行?!?/strong>
二、計(jì)算機(jī)如何幫我們自動(dòng)化完成以上操作呢?
操作系統(tǒng)提供了一系列的API ?如Linux系統(tǒng):
打開 ? ? ? ? ? ? open
讀寫 ? ? ? ? ? ? write/read
光標(biāo)定位 ? ? ?lseek
關(guān)閉 ? ? ? ? ? ? ?close
三、文件打開及創(chuàng)建
打開/創(chuàng)建文件
頭文件:
「#include
#include #include 」
int open(const char *pathname , int flags); //(參數(shù)1:字符指針 指向文件路徑 , 參數(shù)2:整型數(shù)權(quán)限)
int open(const char *pathname , int ?flags , mode_t ?mode); //open 返回值是文件描述符——沒有文件返回值就無法用write(); ?和 ?read();
參數(shù)說明:
*pathname ?: ? //要打開的文件名(含路徑,缺省為當(dāng)前路徑)
flags ? :
O_RDONLY ? ?只讀打開 O_WRONLY ? 只寫打開 O_RDWR ? ? ? 可讀可寫可打卡
「當(dāng)我們附帶了權(quán)限后,打開的文件就只能按照這種權(quán)限來操作?!?/strong>「以上這三個(gè)常數(shù)中應(yīng)當(dāng)只指定一個(gè)?!?/strong>
int?creat(const?char?*filename?,?mode_t?mode)
filename:要?jiǎng)?chuàng)建的文件名(包含路徑,缺省為當(dāng)前路徑)
mode:創(chuàng)建模式??//可讀可寫可執(zhí)行
常見創(chuàng)建模式:
?宏表示???????數(shù)字
?S_IRUSR???????4??????可讀
?S_IWUSR???????2??????可寫
?S_IXUSR???????1??????可執(zhí)行
?S_IRWXU???????7??????可讀,寫,執(zhí)行?
示例代碼:(在路徑/Home/CLC/下創(chuàng)建了file1可讀可寫可執(zhí)行文件)
#include
#include
#include
#include
#include
int?main()
{
???int?fd;
???char?*buf?=?"test";
???fd?=?creat("/home/CLC/file",S_IRWXU);???//S_IRWXU??可讀可寫可執(zhí)行
???return?0;
}
==「下列常數(shù)是可選擇的:」==
1. O_CREA //若文件不存在則創(chuàng)建它。
使用此選項(xiàng)時(shí),「需要同時(shí)說明第三個(gè)參數(shù)mode,用其說明該新文件的存取許可權(quán)限?!?/strong>
「mode:一定是在flags中使用了O_CREAT標(biāo)志,mode記錄待創(chuàng)建的文件的訪問權(quán)限。」
「O_CREAT 若文件不存在則創(chuàng)建它 ? 示例代碼:」
#include
#include
#include
#include
int?main()
{
???int?fd;????//定義整型返回值
???fd?=?open("./file",O_RDWR);??//open指令?打開可讀可寫file文件返回值
???printf("fd?=?%d\n",fd);
???if(fd?==?-1){?????????//若返回值為-1??沒有file文件
??????printf("open?file?failed\n");
??????fd?=?open("./file"?,?O_RDWR?|?O_CREAT?,?0600);???
??????//open?指令?若沒有file文件?”?|?O_CREAT?”?創(chuàng)建file文件?權(quán)限0600??6=4+2??所以是rw??可讀可寫
??????if(fd>0){
??????????printf("creat?file?success\n");
??????}???
???}
???printf("fd=%d\n?,fd");
???return?0;
}
結(jié)果:
「注意:」
「fd = open("./file",O_RDWR);」 ? ? //open指令 打開可讀可寫file文件返回值
「fd = open("./file" , O_RDWR ?| O_CREAT , 0600);」
// ?open 指令 若沒有file文件 ” | O_CREAT ” 創(chuàng)建file文件 權(quán)限0600 ?6=4+2 ?所以是rw ?可讀可寫
權(quán)限0600的含義:
「—表示普通文件 r (4) 可讀 ? ?w(2)可寫 rw 表示可讀可寫 ?x(1)執(zhí)行」「0600 :6=4+2 所以是rw 可讀可寫 0是同組 0其他組」
2. O_EXCL //如果同時(shí)指定了OCREAT , 而文件已經(jīng)存在,則打開失敗或者返回-1
「O_EXCL ?//如果同時(shí)指定了OCREAT , 而文件已經(jīng)存在,則打開失敗或者返回-1 ? 示例代碼:」
#include
#include
#include
#include
int?main(){
???int?fd;
???fd?=?open("./file",O_RDWR?|?O_CREAT?|?O_EXCL?,?0600);
???if(fd?==?-1){?????//若返回值為-1??沒有file文件
?????printf("file?exist\n");
?????return?0;
???}
}
注意:
「fd = open("./file",O_RDWR | O_CREAT | O_EXCL , 0600);」
3. O_APPEND//每次寫時(shí)都加到文件的尾端。
「O_APPEND //每次寫時(shí)都加到文件的尾端 ?示例代碼:」
#include
#include
#include
#include
int??main(){
???int?fd;
???char?*buf?=?"19990330";
???
???fd?=?open("./file",O_RDWR?|?O_APPEND);
???
???printf("open?susceess:?fd?=?%d?\n",?fd);
???
???int?n_write?=?write(fd?,buf,strlen(buf));
???
???if(n_write?!=?-1){
??????????printf("write?%d?byte?to?file\n",n_write);
???}
???close(fd);
???return?0;
}
注意:
「fd = open("./file",O_RDWR | O_APPEND);」
4. O_TRUNC屬性去打開文件時(shí),如果這個(gè)文件中本來是有內(nèi)容的,而且為只讀或者只寫 成功打開,則將其長度截?cái)酁?。
「O_TRUNC屬性去打開文件時(shí),如果這個(gè)文件中本來是有內(nèi)容的,把原先內(nèi)容全部覆蓋掉,示例代碼:」
#include
#include
#include
#include
int?main(){
??int?fd;
??char?*buf?="19990330";
??
??fd?=?open("./file",O_RDWR?|?O_TRUNC);
??printf("open?susceess:fd?=%d\n",fd);
??int?n_write?=?write(fd?,buf?,strlen(buf));
??if(n_write?!=?-1){
????????printf("write?%d?bute?to?file\n",n_write);
??}
??close(fd);
??return?0;
}
注意:
「fd = open("./file",O_RDWR | O_TRUNC);」
ls-l ?是把文件所有內(nèi)容列出來
-rwxr-xr-x 1 CLC book ?8478 ?Fed 9 12:36 ?mode -rw-r --r -- 1 CLC book ? 385 ? ?Fed 9 12:36 ?mode.c -rw ------ 1 CLC ? book ? ? 0 ? ? ?Fed 9 12:44 ?file
—表示普通文件 r (4) 可讀 w(2)可寫 rw 表示可讀可寫 x(1)執(zhí)行
四、文件寫入操作編程
寫入文件:==「write」==
頭文件: ? ?==「#include
「ssize_t write」 (int fd , const void *buf , size_t count);
==「//將緩沖區(qū)buf指針指向內(nèi)存數(shù)據(jù),寫conuct的大小 到 fd里?!?/strong>==
(int fd , const void *buf , size_t count) 參數(shù):(文件描述符 ,【無類型指針是一個(gè)緩沖區(qū)】,寫入文件的大?。?/p>
文件寫入操作示例代碼:
#include
#include
#include
#include
#include
#include
int?main()
{
????int?fd;
????char?*buf?=?"Refuel.CONG";
????fd?=?open("./file",O_RDWR);
????printf("fd=%d\n",fd);
????if(fd?==?-1){
????????printf("open?file?failed\n");
????????fd?=?open("./file",O_RDWR?|?O_CREAT?,?0600);
????????if(fd>0){
????????????printf("creat?file?success\n");
????????}
????}
????//ssize_t?write(int?fd?,?const?void?*buf?,?size_t?count);
????//將緩沖區(qū)buf指針指向內(nèi)存數(shù)據(jù),寫conut大小到fd。
????write(fd,buf,strlen(buf));
????printf("fd=%d\n",fd);
????close(fd);???//關(guān)閉fd文件
????return?0;
}
strlen(); 函數(shù)是用來 真正計(jì)算有效字符長度用strlen 頭文件是:
五、文件讀取操作
讀取文件:==「read」==
頭文件: ?==「#include
「ssize_t read」(int fd , const void *buf , size_t count); ==「//從fd個(gè)文件讀取count個(gè)字節(jié)數(shù)據(jù)放到buf里」==
返回值:若讀取成功,讀多少個(gè)字節(jié)返回多少個(gè)字節(jié),若讀到尾什么都沒讀到返回0,讀取失敗返回-1
文件讀取示例代碼:
#include
#include
#include
#include
#include
#include
int?main()
{
???int?fd;
???char?*buf?="Refuel.CONG";
???fd=?open("./file",O_RDWR);
???printf("fd=%d\n",fd);
???if(fd?==?-1){
???????printf("open?file?failed\n");
???????fd?=?open("./file",?O_RDWR?|?O_CREAT?|?,0600);
???????if(fd>0){
????????????printf("create?file?success\n");
???????}
???}
int?n_write?=?write(fd,buf,strlen(buf));
if(n_write?!=?-1){
??????printf("write%d?byte?to?file\n",n_write);??//若讀取成功,返回讀到的??ite
}
char?*readBuf;
readBuf?=?(char*)malloc(sizeof(char)*n_write+1);
int?n_read?=?read(fd,reafBuf?,?n_write);
printf("read=%d?,?context:%s\n",n_read,readBuf);
close(fd);
return?0;
}
結(jié)果什么都沒讀取到:是因?yàn)楣鈽?biāo)的原因,光標(biāo)在寫入數(shù)據(jù)后,光標(biāo)停在寫完的位置,讀取的時(shí)候光會(huì)變后面,什么也沒有所以讀取不到。
==「解決辦法:」==
把光標(biāo)移動(dòng)到頭。 重新打開文件。
「重新打開文件的方式解決光標(biāo)的問題:」
#include
#include
#include
#include
#include
#include
int?main()
{
???int?fd;
???char?*buf?="Refuel.CONG";
???fd=?open("./file",O_RDWR);
???printf("fd=%d\n",fd);
???if(fd?==?-1){
???????printf("open?file?failed\n");
???????fd?=?open("./file",?O_RDWR?|?O_CREAT?|?,0600);
???????if(fd>0){
????????????printf("create?file?success\n");
???????}
???}
int?n_write?=?write(fd,buf,strlen(buf));
if(n_write?!=?-1){
??????printf("write%d?byte?to?file\n",n_write);??//若讀取成功,返回讀到的??ite
}
close(fd);????????????????????//寫完數(shù)據(jù)后關(guān)閉文件
fd?=?open("./file",O_RDWR);????//重新打開
char?*readBuf;
readBuf?=?(char*)malloc(sizeof(char)*n_write+1);
int?n_read?=?read(fd,reafBuf?,?n_write);
printf("read=%d?,?context:%s\n",n_read,readBuf);
close(fd);
return?0;
}
結(jié)果為:
六、文件光標(biāo)移動(dòng)操作
光標(biāo)移動(dòng):==「lseek」== 頭文件:
==「#include 」 ====「#include 」 ==
宏:
==「SEEK_SET」== ? ?「//指向文件的頭」 ==「SEEK_CUR」== ? 「//指向當(dāng)前光標(biāo)位置」 ==「SEEK_END」== ? 「//指向文件的尾」
「off_t ?lseek」(int fd , off_t 「offset」 , int 「whence」); 作用:「將文件讀寫指針相對(duì) whence 移動(dòng) offset 個(gè)字節(jié)」參數(shù)說明:「(文件描述符,偏移值,固定的位置)」
#include
#include
#include
#include
#include
#include
int?main()
{
???int?fd;
???char?*buf?="Refuel.CONG";
???fd=?open("./file",O_RDWR);
???printf("fd=%d\n",fd);
???if(fd?==?-1){
???????printf("open?file?failed\n");
???????fd?=?open("./file",?O_RDWR?|?O_CREAT?|?,0600);
???????if(fd>0){
????????????printf("create?file?success\n");
???????}
???}
int?n_write?=?write(fd,buf,strlen(buf));
if(n_write?!=?-1){
??????printf("write%d?byte?to?file\n"n_write);?
}
char?*readBuf;
readBuf?=?(char?*)malloc(sizeof?(char)*n_write+1);
lseek?(fd,0,SEEK_SET);???//參數(shù):(文件描述,偏移值,固定的位置)
//lseek(fd,-11?,SEEK_CUR);??//所在光標(biāo)位置往前偏移11個(gè)
int?n_read?=?read(fd?,readBuf,n_write);
printf("read=%d,context:%s\n",n_write,readBuf);
close(fd);
return?0;
lseek (fd,0,SEEK_SET); ? //參數(shù):(文件描述,偏移值,固定的位置) lseek(fd,-11,SEEK_CUR); ?//所在光標(biāo)位置往前偏移11個(gè)
七、文件操作原理簡述
1.文件描述符:
對(duì)于內(nèi)核而言,所有打開文件都由文件描述符引用。文件描述符是一個(gè)非負(fù)整數(shù)。當(dāng)打開一個(gè)現(xiàn)存文件或者創(chuàng)建一個(gè)新文件時(shí),內(nèi)核向進(jìn)程返回一個(gè)文件描述符。當(dāng)讀寫一個(gè)文件時(shí),用open和creat返回的文件描述符標(biāo)識(shí)該文件,將其作為參數(shù)傳遞給read和write。按照慣例,UNIX shell 使用文件描述符0與進(jìn)程的標(biāo)準(zhǔn)輸入相結(jié)合,文件描述符1與標(biāo)準(zhǔn)輸出相結(jié)合,文件描述符2與標(biāo)準(zhǔn)錯(cuò)誤輸出相結(jié)合。STDIN_FILENO 、STDOUT_FILENO、STDERR_FILENO這幾個(gè)宏代替了0,1,2這幾個(gè)數(shù)。
文件描述符,這個(gè)數(shù)字在一個(gè)進(jìn)程中表示一個(gè)特定含義,當(dāng)我們open一個(gè)文件時(shí),操作系統(tǒng)在內(nèi)存中構(gòu)建了一些數(shù)據(jù)結(jié)構(gòu)來表示這個(gè)動(dòng)態(tài)文件,然后返回給應(yīng)用程序一個(gè)數(shù)字作為文件描述符,這個(gè)數(shù)字就和我們內(nèi)存中維護(hù)的這個(gè)動(dòng)態(tài)文件的這些數(shù)據(jù)結(jié)構(gòu)綁定上了,以后我們應(yīng)用程序如果要操作這個(gè)動(dòng)態(tài)文件,只需要用這個(gè)文件描述符區(qū)分。
文件描述符的作用域就是當(dāng)前進(jìn)程,除了這個(gè)進(jìn)程文件描述符就沒有意義了,open函數(shù)打開文件,打開成功返回一個(gè)文件描述符,打開失敗,返回-1。
2.linux系統(tǒng)默認(rèn):
標(biāo)準(zhǔn)描述符:「標(biāo)準(zhǔn)輸入(0) ?標(biāo)準(zhǔn)輸出(1) 標(biāo)準(zhǔn)錯(cuò)誤(3)」
#include
#include
#include
#include
#include
#include
int?main(){
????int?fd;
????char?readBuf[128];
????
????int?n_read?=?read(0,readBuf,5);?????//?0?標(biāo)準(zhǔn)輸入
????int?n_write?=?write(1,readBuf,strlen(readBuf));?//?1?標(biāo)準(zhǔn)輸出
????printf("\n?end!\n");
????return?0;
}

3.操作文件時(shí)候:
「打開/創(chuàng)建文件 ? ——> ? 讀取文件/寫入文件 ?——> ?關(guān)閉文件」==
1、在Linux中要操作一個(gè)文件,一般是先open打開一個(gè)文件,得到文件描述符,然后對(duì)文件進(jìn)行讀寫操作(或其他操作),最后是close關(guān)閉文件即可。
2、強(qiáng)調(diào)一點(diǎn):我們對(duì)文件進(jìn)行操作時(shí),一定要先打開文件,打開成功之后才能操作,如果打開失敗,就不用進(jìn)行后邊的操作了,「最后讀寫完成后,一定要關(guān)閉文件,否則會(huì)造成文件損壞?!?/strong>
3、「文件平時(shí)是存放在塊設(shè)備中的文件系統(tǒng)文件中的,我們把這種文件叫靜態(tài)文件」,當(dāng)我們?nèi)pen打開一個(gè)文件時(shí),linux內(nèi)核做的操作包括:內(nèi)核在進(jìn)程中建立一個(gè)打開文件的數(shù)據(jù)結(jié)構(gòu),記錄下我們打開的這個(gè)文件;內(nèi)核在內(nèi)存中申請(qǐng)一段內(nèi)存,并且將靜態(tài)文件的內(nèi)容從塊設(shè)備中讀取到內(nèi)核中特定地址管理存放(叫動(dòng)態(tài)文件)。read write 都是對(duì)動(dòng)態(tài)文件進(jìn)行操作
4、打開文件以后,以后對(duì)這個(gè)文件的讀寫操作,都是針對(duì)內(nèi)存中的這一份動(dòng)態(tài)文件的,而并不是針對(duì)靜態(tài)文件的。當(dāng)然我們對(duì)動(dòng)態(tài)文件進(jìn)行讀寫以后,此時(shí)內(nèi)存中動(dòng)態(tài)文件和快設(shè)備文件中的靜態(tài)文件就不同步了,當(dāng)我們close關(guān)閉動(dòng)態(tài)文件名,close內(nèi)部內(nèi)核將內(nèi)存中的動(dòng)態(tài)文件的內(nèi)容去更新(同步)塊設(shè)備中的靜態(tài)文件。
5、為什么這么設(shè)計(jì),不直接對(duì)塊設(shè)備直接操作。「塊」(假設(shè)有100字節(jié))設(shè)備本身讀寫非常不靈活,是按塊讀寫的,最小只讀100字節(jié),而「內(nèi)存是擠字節(jié)單位操作的可而具可以隨機(jī)操作,很靈活」。
「靜態(tài)文件」放入磁盤中的文件是靜態(tài)文件, 如:桌面上的文件.jpg
「動(dòng)態(tài)文件」open靜態(tài)文件后,會(huì)在linux內(nèi)核產(chǎn)生結(jié)構(gòu)體記錄文件 ? 如:fd ? 信息節(jié)點(diǎn),buf(內(nèi)容,內(nèi)存)
調(diào)用close時(shí)候,會(huì)把所有信息緩存到磁盤中
八、文件操作編程小練習(xí)—實(shí)現(xiàn)cp指令代碼:
==「cp ( src.c ?//源文件 ,dest.c //復(fù)制到的目標(biāo)文件)」==
「實(shí)現(xiàn)cp操作:」
1.c語言參數(shù):./a.out ?_ _ ==2.實(shí)現(xiàn)思路:==
打開src.c 讀src到buf 創(chuàng)建/打開dest.c 將buf寫入dest.c close兩個(gè)文件
==c語言參數(shù):==「// 參數(shù)(argc是數(shù)組)(argv是二級(jí)指針是包含數(shù)組的數(shù)組:是argv里的每一項(xiàng)都是一個(gè)數(shù)組)」
#include
int?main(?int??argc?,?char?**agrv)????//?參數(shù)(argc是數(shù)組)(argv是包含數(shù)組的數(shù)組:是argv里的每一項(xiàng)都是一個(gè)數(shù)組)
{
????printf("totol?params:%d\n",argc);
????printf("No.1??params:%d\n",argv[0]);
????printf("No.2??params:%d\n",argv[1]);
????printf("No.3??params:%d\n",argv[2]);?
???return?0;
}
輸入 :./a.out ? des ?src 結(jié)果:totol params : 3 No.1 ?params : ?./a.out No.2 ?params : ?des No.3 ?params : src
「實(shí)現(xiàn)mycp操作代碼:」
#include
#include
#include
#include
#include
#include
int?main(int?argc?,char?**argv){
????int?fdSrc;
????int?fdDest;
????char?*readBuf?=?NULL;
????if(argc?!=?3){
????????printf("param?error\n");
????????exit(-1);
????}
????
fdSrc?=?open(argv[1],O_RDWR);??????//1.?打開fdSrc.c(源文件)
int?size?=?lseek(fdSrc?,0,?SEEK_END);???//光標(biāo)記錄文件大小
lseek(fdSrc?,?0,?SEEK_SET);???//?。∏f記得把?光標(biāo)回到頭
readBuf?=?(char?*)malloc(sizeof(char)?*size+8);??//開辟readBuf空間大小
int?n_read?=?read(fdSrc,readBuf,size);???//2.?讀取fdSrc(源文件)到readBuf緩沖區(qū)
fdDest?=?open(argv[2],O_RDWR?|?O_CREAT?|?O_TRUNC?,0600);???//3.?打開/創(chuàng)建fdDest.c
int?n_write?=?write(fdDest,readBuf,strlen(readBuf));??//4.?將readbuf寫入到fdDest.c
close(fdSrc);????//5.關(guān)閉兩個(gè)文件
close(fdDest);
return?0;
}
mycp容易出現(xiàn)的小問題—實(shí)現(xiàn)優(yōu)化:
「用 lseek來光標(biāo)計(jì)算size數(shù)組」
char?*readBuf?=?NULL;
?int?size?=?lseek(fdSrc,0,SEEK_END);
?????lseek(fdSrc?,?0?,SEEK_SET);
?????readBuf?=?(char?*)malloc(sizeof(char)*size?+?8);
「若要是拷貝大于1024的文件就不行」
?int?n_read?=?read(fdSrc,readBuf,size);????//讀取大小用lseek查出的大小.
3.「目標(biāo)文件存在并且存在一些數(shù)據(jù),拷貝就會(huì)覆蓋了原來數(shù)據(jù)的一部分」
解決方法:「O_TRUNC」 屬性去打開文件時(shí),如果這個(gè)文件中本來是有內(nèi)容的,而且為只讀或者只寫成功打開,則將其長度截?cái)酁?
fdDes?=?open(argv[2],O_RDWR|O_CREAT|O_TRUNC,0600);
九、文件編程小應(yīng)用之修改程序的配置文件
==「(工作中常用)」== 配置文件的修改
例如:SPEED=5 LENG=100 SCORE=90 LEVEL=95
「修改指定內(nèi)容的思路:」
找到(要修改的)位置 (修改的位置)往后移動(dòng)到(要改的值 )
3. 修改要改的值
找尋修改位置時(shí)候,用到 「strstr()」 函數(shù);功能:用來檢索子串在字符串中首次出現(xiàn)的位置
「修改LENG的值 示例代碼:」
#include
#include
#include
#include
#include
#include
#include
int?main(int?argc?,?char?**argv){
???int?fdSrc;
???char?*readBuf=NULL;
???if(argc?!=?2?){
???????printf("pararm?error\n");
???????exit(-1);
???}
??fdSrc?=?open(argv[1],O_RDWR);
??int?size?=?lseek(fdSrc,0,SEEK_END);
??lseek?(fdSrc,0,SEEK_SET);
??
??readBuf?=(char?*)malloc(sizeof(char)*size+8);
??int?n_read=?read(fdSrc,readBuf,size);
??
??char?*p=strstr(readBuf,"LENG=");?//找到(要修改的)位置???
??//參數(shù)1?要找的源文件??2.“要找的字符串”
??if(p==NULL){
????printf("not?found\n");
????exit(-1);
??}
??p=p+strlen("LENG=");??//移動(dòng)字符串個(gè)字節(jié)
??*p='0';??????//*p??取內(nèi)容
??
lseek?(fdSrc,0,SEEK_SET);
int?n_write?=write(fdSrc,readBuf,strlen(readBuf));
close(fdSrc);
return?0;
}
「可以把封裝成一個(gè)函數(shù):」
void?*changefile(int?fd,char?*readbuf,char*?f,char?t){
????????char?*p?=?strstr(readbuf,f);
????????if(p?==?NULL){
???????????printf("no?found\n");
???????????exit(-1);
????????}
????????p?=?p?+?strlen(f);
????????*p?=?t;
?????}
int?main(int?argc,char?**argv)
{
??????changefile(fdSrc,readBuf,"LENG=",'6');
}
十、寫一個(gè)整數(shù)到文件
「ssize_t ?write」(int fd , const void *buf , size_t count);
//將緩沖區(qū)buf指針指向內(nèi)存數(shù)據(jù),寫conut大小到fd.
「ssize_t ?read」(int fd , const void *buf , size_t count);
//從fd個(gè)文件讀取count個(gè)字節(jié)數(shù)據(jù)放到buf里
1.寫入整型數(shù)代碼:
#include
#include
#include
#include
#include
#include
#include
int?main(){
???int?fd;
???int?data?=?100;
???int?data2?=?0;
???fd=open("./flie1",O_RDWR);
???
???int?n_write?=write(fd,?&data,?sizeof(int));
???lseek(fd,0,SEEK_SET);
???int?n_read?=read(fd,?&data2,?sizeof(int));
???printf("read?%d\n",data2);
???close(fd);
???return?0;
}

2.寫入結(jié)構(gòu)體代碼(1):
struct?Test
{
???int?a;
???char?c;
};
int?main(){
???int?fd;
???int?Test?data?=?{100,'a'};
???int?Test?data2?;
???fd=open("./flie1",O_RDWR);
???
???int?n_write?=write(fd,?&data,?sizeof(struct?Test));
???lseek(fd,0,SEEK_SET);
???int?n_read?=read(fd,?&data2,?sizeof(struct?Test));
???printf("read?%d?%s\n",data2.a,data2.c);
???close(fd);
???return?0;
}
3.寫入結(jié)構(gòu)體代碼(2):
struct?Test
{
???int?a;
???char?c;
};
int?main(){
???int?fd;
???int?Test?data[2]?=?{{100,'a'},{101,'b'}};
???int?Test?data2[2];
???fd=open("./flie1",O_RDWR);
???
???int?n_write?=write(fd,?&data,?sizeof(struct?Test)*2);
???lseek(fd,0,SEEK_SET);
???int?n_read?=read(fd,?&data2,?sizeof(struct?Test)*2);
???printf("read?%d?%s\n",data2[0].a,data2[0].c);
???printf("read?%d?%s\n",data2[1].a,data2[1].c);
???close(fd);
???return?0;
}
「注意寫入/讀入的 大小:」 ?sizeof(struct Test) 「乘2」
「緩沖區(qū)可以寫入 :整數(shù),字符,結(jié)構(gòu)體等」
十一、標(biāo)準(zhǔn)C庫對(duì)文件操作引入
1. open 和 fopen 的區(qū)別
「1.來源」
open是UNIX系統(tǒng)調(diào)用函數(shù),返回的是文件描述符,它是文件在文件描述符表里的索引。
fopen是ANSIC標(biāo)準(zhǔn)中的c語言庫函數(shù),在不同的系統(tǒng)中應(yīng)該調(diào)用不同的內(nèi)核API,返回值是一個(gè)指向文件結(jié)構(gòu)的指針。
「2.移植性」
這一點(diǎn)從上面的來源就可以推斷出來,fopen是C標(biāo)準(zhǔn)函數(shù),因此用有良好的移植性;而oprn是UNIX系統(tǒng)調(diào)用,移植性有限。如windows下相似的功能使用API函數(shù)。
「3.適用范圍」
open返回文件描述符,而文件描述符是UNIX系統(tǒng)下的一個(gè)重要概念,UNIX下的一切設(shè)備都是文件的形式操作,如網(wǎng)絡(luò)套件字,硬件設(shè)備(驅(qū)動(dòng))等。當(dāng)然包括操作普通正規(guī)文件。fopen是用來操縱普通正規(guī)文件的。
「4.緩沖」
「緩沖文件系統(tǒng)」
緩沖文件系統(tǒng)的特點(diǎn)是:在內(nèi)存開辟一個(gè)“緩沖區(qū)”,為程序中的每一個(gè)文件使用;當(dāng)執(zhí)行讀文件的操作時(shí),從磁盤文件將數(shù)據(jù)先讀入內(nèi)存“緩沖區(qū)”,裝滿后再從內(nèi)存“緩沖區(qū)”依此讀出需要的數(shù)據(jù)。執(zhí)行寫文件的操作時(shí),先將數(shù)據(jù)寫入內(nèi)存“緩沖區(qū)”,待內(nèi)存緩沖區(qū)”裝滿后再寫入文件。由此可以看出,內(nèi)存“緩沖區(qū)”的大小,影響著實(shí)際操作外存的次數(shù),內(nèi)存“緩沖區(qū)”越大,則操作外存的次數(shù)就少,執(zhí)行速度就快、效率高。一般來說,文件“緩沖區(qū)”的大小隨機(jī)器而定。fopen, fclose, fread, fwrite, fgetc, fgets. fputc, fputs, freopen, fseek. ftell, rewind等。
「非緩沖文件系統(tǒng)」
緩沖文件系統(tǒng)是借助文件結(jié)構(gòu)體指針來對(duì)文件進(jìn)行管理,通過文件指針來對(duì)文件進(jìn)行訪問,既可以讀寫字符、字符電、格式化數(shù)據(jù),也可以讀寫二進(jìn)制數(shù)據(jù)。非緩沖文件系統(tǒng)依賴于操作系統(tǒng),通過操作系統(tǒng)的功能對(duì)文件進(jìn)行讀寫,是系統(tǒng)級(jí)的輸入輸出,它不設(shè)文件結(jié)構(gòu)體指針,只能讀寫二進(jìn)制文件,但效率高、速度快,由于ANSI標(biāo)準(zhǔn)不再包括非緩沖文件系統(tǒng),因此建議大家最好不要選擇它.open,close, read, write, getc, getchar, putc, putchar等。
一句話總結(jié)一下,就是open無緩沖,fopen有緩沖。前者與read,write等配合使用,后者與freadfwrite等配合使用
使用fopen函數(shù),由于在用戶態(tài)下就有了緩沖,因此進(jìn)行文件讀寫操作的時(shí)候就減少了用戶態(tài)和內(nèi)核態(tài)的切換(切換到內(nèi)核態(tài)調(diào)用還是需要調(diào)用系統(tǒng)調(diào)用API:read,write);而使用open函數(shù),在文件讀寫時(shí)則每次都需要進(jìn)行內(nèi)核態(tài)和用戶態(tài)的切換;表現(xiàn)為,如果順序訪問文件,fopen系列的函數(shù)要比直接調(diào)用open系列的函數(shù)快;如果隨機(jī)訪問文件則相反。這樣一總結(jié)梳理,相信大家對(duì)于兩個(gè)函數(shù)及系列函數(shù)有了一個(gè)更全面清晰的認(rèn)識(shí),也應(yīng)該知道在什么場合下使用什么樣的函數(shù)更合適 效率更高。
2. fopen(); fwrite(); fread(); 方式寫入數(shù)據(jù)
==FILE ?*「fopen」 ?(const char *path ,const char *mode);==
參數(shù)說明:path :路徑 ? mode ?:用什么方式打開
返回值:FILE 類型
mode 打開模式:
| 模式指令 | 功能說明 |
|---|---|
| r | 只讀方式打開一個(gè)文本文件 |
| rb | 只讀方式打開一個(gè)二進(jìn)制文件 |
| w | 只寫方式打開一個(gè)文本文件 |
| wb | 只寫方式打開一個(gè)二進(jìn)制文件 |
| a | 追加方式打開一個(gè)文本文件 |
| ab | 追加方式打開一個(gè)二進(jìn)制文件 |
| r+ | 可讀可寫方式打開一個(gè)文本文件 |
| rb+ | 可讀可寫方式打開一個(gè)二進(jìn)制文件 |
| w+ | 可讀可寫方式創(chuàng)建一個(gè)文本文件 |
| wb+ | 讀可寫方式生成一個(gè)二進(jìn)制文件 |
| a+ | 可讀可寫追加方式打開一個(gè)文本文件 |
| ab+ | 可讀可寫方式追加一個(gè)二進(jìn)制文件 |
「寫入:」==size_t ? 「fwrite」 ?(const void *ptr ?, size_t size ?, size_t nmemb ?, FILE *stream);==
ptr ? ? 緩沖區(qū) 等同于(buf)
size ?一個(gè)字符大?。╯izeof char) 3. nmemb ?個(gè)數(shù)
4. stream (哪個(gè)文件) which file
「讀?。骸?/strong>==size_t ?「fread」 ?(const void *ptr ,size_t size ,size_t nmemb ,FILE *stream);==
「光標(biāo)問題:」==int ?「fseek」 ?(FILE *stream ?, long offset ,int whence);==
「示例代碼:」
#include
#include
int?main()
{
FILE?*fp;
char?*str?=?"Refuel.CONG";
char?readBuf[128]={0};
fp?=?fopen("./CONG.txt","w+");???//可讀可寫方式創(chuàng)建一個(gè)文本文件?
fwrite(str?sizeof(char),strlen(str),fp);
//一次性寫一個(gè)char?寫str個(gè)字節(jié),到fp里
fseek(fp,0,SEEK_SET);
fread(readBuf,sizeof(char),strlen(str),fp);
//從fp里?一次讀一個(gè)char?讀str個(gè)?讀到readBuf里去
printf("read?data:%s\n",readBuf);
fclose(fp);
return?0;
}


也可改寫:fread (readBuf , ?sizeof(char) , ?* strlen(str) , 1 ?,fp);
//讀*strlen(str)個(gè) ?讀 ?1 次
3. n_read 和 n_write 的返回值
「n_read 和 n_write 的返回值取決于第三個(gè)參數(shù)」==
int?n_fwrite?=?fwrite(str?sizeof(char)*strlen(str),1,fp);
int?n_fread?=?fread(str?sizeof(char)*strlen(str),1,fp);
printf("read=%d,write=%d\n",n_read,n_write);
結(jié)果:n_read= 1 n_write =1
4. n_fread 和 n_fwrite 返回值區(qū)別
?int?n_fread?=?fread(str?sizeof(char)*strlen(str),100,fp);
?printf("n_read=%d\n",n_read);
結(jié)果為 :n_read = 1
「但是如果寫100結(jié)果就會(huì)不同」
?int?n_fwrite?=?fwrite(str?sizeof(char)*strlen(str),100,fp);
?printf("n_write=%d\n",n_write);
結(jié)果為 :n_write= 100
5. 標(biāo)準(zhǔn)c庫寫入結(jié)構(gòu)體到文件
「fwrite()寫入結(jié)構(gòu)體代碼:」
#include
#include
struct?Test
{
????int??a;
????char?c;
};
int?main()
{
FILE?*fp;
struct?Test?data1?={1100,'a'};
struct?Test?data2;
fp?=?fopen("./CONG.txt","w+");???//可讀可寫方式創(chuàng)建一個(gè)文本文件?
int?n_fwrite?=?fwrite(&data?,?sizeof(stsuct?Test)?,1,?fp);
fseek(fp,0,SEEK_SET);
int?n_fread?=?fread(&data?,?sizeof(stsuct?Test)?,1,?fp);
printf("read?=%d,%s\n",data2.a,data2.c);
fclose(fp);
return?0;
}
結(jié)果:read = 1100 , a
6. fgetc(); ?fputc(); ?feof() 的使用方法;
==「讀字符函數(shù) :fgetc() 函數(shù)的用法」== 作用:從指定的文件中讀一個(gè)字符, 函數(shù)調(diào)用的形式為:char ch//字符變量 = fgetc(fp // 文件指針); 我們可以將讀取到的數(shù)據(jù)給到一個(gè)字符變量存儲(chǔ)。
「面對(duì)要讀取的數(shù)據(jù)繁多的情況,為了減少程序運(yùn)行的時(shí)間復(fù)雜度」,要用到 ==「fgets();」== 「fgets();」 ?功能是從指定的文件讀取一個(gè)字符串到字符數(shù)組中。函數(shù)的調(diào)用形式為:fgets(字符數(shù)組名,n,文件指針); 參數(shù):n 為一個(gè)正整數(shù)。表示從文件中讀出的字符串不超過n-1個(gè)字符,在讀入的最后一個(gè)字符后加上字符串結(jié)束標(biāo)志'0',說通俗易懂點(diǎn)就是讀多少?
printf("%s\n",str);?//循環(huán)讀取所有數(shù)據(jù)?while(fgets(str?,100?,fp)){?
//循環(huán)讀取所有數(shù)據(jù),直到fets讀到’\0‘
????printf("%s\n",str);?}?fclose(fp);?return?0?;?```
==「fputc() 函數(shù)的用法」==
int fputc(int c , FILE *stream); 功能:把 c 寫入 文件stream里
==「feof() 函數(shù)的用法」==
int ?feof (FILE *stream );作用:(「是否到尾巴的位置」):「測試在沒到達(dá)文件尾巴返回0,到達(dá)尾巴返回 非0」
「feof() 函數(shù)使用代碼:」
#include
#include
int?main(){
??FILE?*fp;
??int?i;
??char?c;
??fp?=?fopen("./test.txt",r);
??//沒到達(dá)文件尾巴返回0,到達(dá)尾巴返回非0
??while(!feof(fp)){??
??//沒到尾巴時(shí)返回0,取反?進(jìn)入while??當(dāng)?shù)竭_(dá)尾巴返回非0??取反=0?退出while
??????c=fgetc(fp);
??????printf("%c",c);
??}
??fclose(fp);
??return?0;
}
「fputc寫入文件代碼:」
#include
#include
int?main(){
??FILE?*fp;
??int?i;
??char?*str?="Refuel.CONG";
??int?len?=?sizeof(str);
??fp?=?fopen("./test.txt","w+");
??if(fp?==??NULL){
????printf("打開文件出現(xiàn)錯(cuò)誤\n");
????exit(-1);
??}
??for(i=0;i?????fputc(*str,fp);
?????str++;
??}
??fclose(fp);
??return?0;
}
文件編程就到這里結(jié)束了!??!
文件編程就到這里結(jié)束了?。?!
原文鏈接 https://blog.csdn.net/weixin_44278698/article/details/123581754?utm_source=app&app_version=5.2.1&code=app_1562916241&uLinkId=usr1mkqgl919blen
推薦閱讀:
最近 Github 上爆火的 Chrome 生產(chǎn)力神器 Omni 是什么鬼?
5T技術(shù)資源大放送!包括但不限于:C/C++,Linux,Python,Java,PHP,人工智能,單片機(jī),樹莓派,等等。在公眾號(hào)內(nèi)回復(fù)「1024」,即可免費(fèi)獲?。?/span>


