扣丁學(xué)堂Linux系統(tǒng)編程之簡(jiǎn)單文件IO操作
2018-01-31 14:45:41
1211瀏覽
在Linux的世界里,一切設(shè)備皆文件。我們可以系統(tǒng)調(diào)用中I/O的函數(shù)(I:input,輸入;O:output,輸出),對(duì)文件進(jìn)行相應(yīng)的操作(open()、close()、write()、read()等)。
首先使用Linux的文件API,經(jīng)常看見(jiàn)一個(gè)東西,叫做文件描述符。打開現(xiàn)存文件或新建文件時(shí),系統(tǒng)(內(nèi)核)會(huì)返回一個(gè)文件描述符,文件描述符用來(lái)指定已打開的文件。這個(gè)文件描述符相當(dāng)于這個(gè)已打開文件的標(biāo)號(hào),文件描述符是非負(fù)整數(shù),是文件的標(biāo)識(shí),操作這個(gè)文件描述符相當(dāng)于操作這個(gè)描述符所指定的文件。
什么是文件描述符?
(1)文件描述符其實(shí)實(shí)質(zhì)是一個(gè)數(shù)字,這個(gè)數(shù)字在一個(gè)進(jìn)程中表示一個(gè)特定的含義,當(dāng)我們open打開一個(gè)文件時(shí),操作系統(tǒng)在內(nèi)存中構(gòu)建了一些數(shù)據(jù)結(jié)構(gòu)來(lái)表示這個(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è)文件描述符進(jìn)行區(qū)分。
(2)文件描述符就是用來(lái)區(qū)分一個(gè)程序打開的多個(gè)文件的。
(3)文件描述符的作用域就是當(dāng)前進(jìn)程,出了當(dāng)前進(jìn)程這個(gè)文件描述符就沒(méi)有意義了
(4)文件描述符fd的合法范圍是0或者一個(gè)正數(shù),不可能是一個(gè)負(fù)數(shù)
(5)open返回的fd必須記錄好,以后向這個(gè)文件的所有操作都要靠這個(gè)fd去對(duì)應(yīng)這個(gè)文件,最后關(guān)閉文件時(shí)也需要fd去指定關(guān)閉這個(gè)文件。如果在我們關(guān)閉文件前fd丟了,那么這個(gè)文件就沒(méi)法關(guān)閉了也沒(méi)法讀寫了
1)打開與讀取文件
#include
#include
#include
#include
#include
intmain(intargc,charconst*argv[]){
intfd=-1;//文件描述符
//打開文件
fd=open("ghostwu.txt",O_RDWR);
if(-1==fd){
printf("文件打開失敗\n");
}else{
printf("文件打開成功,fd=%d\n",fd);
}
//讀取文件
intcount=0;
charbuf[20];
count=read(fd,buf,50);
if(-1==count){
printf("文件讀取失敗\n");
}else{
printf("文件讀取成功,實(shí)際讀取的字節(jié)數(shù)目為:%d\n內(nèi)容為%s\n",count,buf);
}
//關(guān)閉文件
close(fd);
return0;
}
需要在當(dāng)前目錄下存在ghostwu.txt這個(gè)文件,否則打開的時(shí)候失敗,這里涉及2個(gè)api
intopen(constchar*pathname,intflags);
open非常簡(jiǎn)單,第一個(gè)參數(shù)就是文件路徑,第二個(gè)是文件模式,在man手冊(cè)中還提供了其他幾種方式。
ssize_tread(intfd,void*buf,size_tcount);
第一個(gè)參數(shù)為文件描述符,就是open返回的那個(gè)值
第二個(gè)參數(shù)buf用來(lái)存儲(chǔ)從文件中讀取的內(nèi)容
第三個(gè)參數(shù),表示希望從文件中讀取的內(nèi)容(注:這個(gè)count數(shù)字可以隨便給,最終以返回的實(shí)際數(shù)目(read的返回值)為準(zhǔn)
2)打開與寫入文件
#include
#include
#include
#include
#include
#include
intmain(intargc,charconst*argv[]){
intfd=-1;//文件描述符
//打開文件
fd=open("ghostwu.txt",O_RDWR);
if(-1==fd){
printf("文件打開失敗\n");
}else{
printf("文件打開成功,fd=%d\n",fd);
}
//寫文件
charbuf[]="IloveLinux,Linuxisveryverygood!!!";
intcount=0;
count=write(fd,buf,strlen(buf));
if(-1==count){
printf("文件寫入失敗\n");
}else{
printf("文件寫入成功,實(shí)際寫入的字節(jié)數(shù)目為:%d\n",count);
}
//關(guān)閉文件
close(fd);
return0;
}
ssize_twrite(intfd,constvoid*buf,size_tcount);
第一個(gè)參數(shù)為文件描述符,就是open返回的那個(gè)值
第二個(gè)參數(shù)buf用來(lái)存儲(chǔ)寫入的內(nèi)容
第三個(gè)參數(shù),表示希望寫入的文件大小
3)open的一些flag參數(shù)
1,只讀與只寫權(quán)限
#include
#include
#include
#include
#include
intmain(intargc,charconst*argv[]){
intfd=-1;//文件描述符
//打開文件,O_RDONLY:只讀權(quán)限,打開之后的文件只能讀取,不能寫入
//打開文件,O_WRONLY:只寫權(quán)限,打開之后的文件只能寫入,不能讀取
//fd=open("ghostwu.txt",O_RDONLY);
fd=open("ghostwu.txt",O_WRONLY);
if(-1==fd){
printf("文件打開失敗\n");
}else{
printf("文件打開成功,fd=%d\n",fd);
}
//讀取文件
intcount=0;
charbuf[41];
count=read(fd,buf,38);
if(-1==count){
printf("文件讀取失敗\n");
}else{
printf("文件讀取成功,實(shí)際讀取的字節(jié)數(shù)目為:%d\n內(nèi)容為%s\n",count,buf);
}
//關(guān)閉文件
close(fd);
return0;
}
2,清空與追加
#include
#include
#include
#include
#include
#include
intmain(intargc,charconst*argv[]){
intfd=-1;//文件描述符
//打開文件
//在O_RDWR模式下,對(duì)于一個(gè)已經(jīng)存在的文件,且有內(nèi)容,那么寫入文件會(huì)覆蓋對(duì)應(yīng)大小的源文件內(nèi)容【不是完全覆蓋】
//fd=open("ghostwu.txt",O_RDWR);
//在具有寫入權(quán)限的文件中,使用O_TRUNC會(huì)先把原來(lái)的內(nèi)容清除,再寫入新的內(nèi)容
//fd=open("ghostwu.txt",O_RDWR|O_TRUNC);
//在具有寫入權(quán)限的文件中,使用O_APPEND會(huì)把新內(nèi)容追加到原來(lái)內(nèi)容的后面
//fd=open("ghostwu.txt",O_RDWR|O_APPEND);
//在具有寫入權(quán)限的文件中,使用O_APPEND和O_TRUNCO_TRUNC起作用,會(huì)把原來(lái)的內(nèi)容清除,再寫入新的內(nèi)容
fd=open("ghostwu.txt",O_RDWR|O_APPEND|O_TRUNC);
if(-1==fd){
printf("文件打開失敗\n");
return-1;
}else{
printf("文件打開成功,fd=%d\n",fd);
}
//寫文件
charbuf[]="newcontent";
intcount=0;
count=write(fd,buf,strlen(buf));
if(-1==count){
printf("文件寫入失敗\n");
return-1;
}else{
printf("文件寫入成功,實(shí)際寫入的字節(jié)數(shù)目為:%d\n",count);
}
//關(guān)閉文件
close(fd);
return0;
}
3,文件存在已否,創(chuàng)建文件與設(shè)置權(quán)限
#include
#include
#include
#include
#include
#include
intmain(intargc,charconst*argv[]){
intfd=-1;
//fd=open("ghostwu.txt",O_RDWR|O_CREAT|O_EXCL);
/*
文件不存在:
創(chuàng)建這個(gè)文件并打開成功
文件存在:
再次運(yùn)行時(shí)(文件已經(jīng)創(chuàng)建成功,存在了),這時(shí)打開失敗
*/
//fd=open("ghostwu.txt",O_RDWR|O_CREAT);
fd=open("ghostwu.txt",O_RDWR|O_CREAT|O_EXCL,666);
if(-1==fd){
printf("文件打開失敗,錯(cuò)誤號(hào):%d\n",errno);
perror("open");
return-1;
}else{
printf("文件打開成功\n");
}
close(fd);
return0;
}
上面用到了一個(gè)函數(shù)perror,errno和perror:
1)errno就是errornumber,意思就是錯(cuò)誤號(hào)碼。linux系統(tǒng)中對(duì)各種常見(jiàn)錯(cuò)誤做了個(gè)編號(hào),當(dāng)函數(shù)執(zhí)行錯(cuò)誤時(shí),函數(shù)會(huì)返回一個(gè)特定的errno編號(hào)來(lái)告訴我們這個(gè)函數(shù)到底哪里錯(cuò)了
2)errno是由操作系統(tǒng)來(lái)維護(hù)的一個(gè)全局變量,操作系統(tǒng)內(nèi)部函數(shù)都可以通過(guò)設(shè)置errno來(lái)告訴上層調(diào)用者究竟剛才發(fā)生了一個(gè)什么錯(cuò)誤
3)errno本身實(shí)質(zhì)是一個(gè)int類型的數(shù)字,每個(gè)數(shù)字編號(hào)對(duì)應(yīng)一種錯(cuò)誤。當(dāng)我們只看errno時(shí)只能得到一個(gè)錯(cuò)誤編號(hào)數(shù)字,并不知道具體錯(cuò)在哪里,所以:linux系統(tǒng)提供了一個(gè)函數(shù)perror(意思printerror),perror函數(shù)內(nèi)部會(huì)讀取errno并且將這個(gè)不好認(rèn)的數(shù)字直接給轉(zhuǎn)成對(duì)應(yīng)的錯(cuò)誤信息字符串,然后打印出來(lái)
4,lseek用來(lái)移動(dòng)文件內(nèi)部指針
簡(jiǎn)單應(yīng)用:統(tǒng)計(jì)文件大小
#include
#include
#include
#include
#include
#include
intmain(intargc,charconst*argv[]){
if(argc!=2){
printf("usage:%s%s\n",argv[0],"filename");
return-1;
}
intfd=-1;
fd=open(argv[1],O_RDWR);
if(-1==fd){
printf("文件打開失敗,錯(cuò)誤號(hào):%d\n",errno);
perror("open");
return-1;
}else{
printf("文件打開成功\n");
}
//把指針移動(dòng)到文件末尾,就是文件的大小
intcount=lseek(fd,0,SEEK_END);
printf("文件大小為%d\n",count);
close(fd);
return0;
}
------------------------------------------分割線------------------------------------------
一、同一個(gè)進(jìn)程,多次打開同一個(gè)文件,然后讀出內(nèi)容的結(jié)果是:分別讀【我們使用open兩次打開同一個(gè)文件時(shí),fd1和fd2所對(duì)應(yīng)的文件指針是不同的2個(gè)獨(dú)立的指針】
#include
#include
#include
#include
#include
#include
intmain(intargc,charconst*argv[]){
intfd1=-1;
intfd2=-1;
charbuf1[20]={0};
charbuf2[20]={0};
intcount1=0;
intcount2=0;
fd1=open("ghostwu.txt",O_RDWR);
if(-1==fd1){
printf("文件打開失敗\n");
perror("open");
return-1;
}else{
printf("文件打開成功,fd1=%d\n",fd1);
}
count1=read(fd1,buf1,5);
if(-1==count1){
printf("文件讀取失敗\n");
perror("read");
}else{
printf("文件讀取成功,讀取的內(nèi)容是%s\n",buf1);
}
fd2=open("ghostwu.txt",O_RDWR);
if(-1==fd1){
printf("文件打開失敗\n");
perror("open");
return-1;
}else{
printf("文件打開成功,fd2=%d\n",fd1);
}
count2=read(fd2,buf2,10);
if(-1==count2){
printf("文件讀取失敗\n");
perror("read");
}else{
printf("文件讀取成功,讀取的內(nèi)容是%s\n",buf2);
}
close(fd1);
close(fd2);
return0;
}
二、同一個(gè)進(jìn)程,多次打開同一個(gè)文件,然后寫入內(nèi)容的結(jié)果是:分別寫,當(dāng)使用O_APPEND,就是接著寫
#include
#include
#include
#include
#include
#include
#include
intmain(intargc,charconst*argv[]){
intfd1=-1;
intfd2=-1;
charbuf1[]="ghost";
charbuf2[]="wu";
intcount1=0;
intcount2=0;
fd1=open("ghostwu.txt",O_RDWR);
if(-1==fd1){
printf("文件打開失敗\n");
perror("open");
return-1;
}else{
printf("文件打開成功,fd1=%d\n",fd1);
}
count1=write(fd1,buf1,strlen(buf1));
if(-1==count1){
printf("文件寫入失敗\n");
perror("write");
}else{
printf("文件寫入成功,寫入的內(nèi)容是%s\n",buf1);
}
fd2=open("ghostwu.txt",O_RDWR);
if(-1==fd1){
printf("文件打開失敗\n");
perror("open");
return-1;
}else{
printf("文件打開成功,fd2=%d\n",fd1);
}
count2=write(fd2,buf2,strlen(buf2));
if(-1==count2){
printf("文件寫入失敗\n");
perror("write");
}else{
printf("文件寫入成功,寫入的內(nèi)容是%s\n",buf2);
}
close(fd1);
close(fd2);
return0;
}
上面代碼保持不變,再寫入的時(shí)候加入flag標(biāo)志:
fd1=open("ghostwu.txt",O_RDWR|O_APPEND);
fd2=open("ghostwu.txt",O_RDWR|O_APPEND);
三、dup后的fd和原來(lái)打開文件的fd指向的是同一個(gè)文件,同時(shí)對(duì)這個(gè)文件寫入時(shí),是接著寫
#include
#include
#include
#include
#include
#include
intmain(intargc,charconst*argv[]){
intfd1=-1;
intfd2=-1;
fd1=open("ghostwu.txt",O_RDWR);
if(-1==fd1){
perror("open");
return-1;
}else{
printf("文件打開成功:fd=%d\n",fd1);
}
//dup后的文件,同時(shí)write是接著寫入
fd2=dup(fd1);
printf("文件dup成功:fd=%d\n",fd2);
//分別向fd1和fd2指向的文件寫入
charbuf1[]="ghost";
charbuf2[]="wu";
intcount1=-1,count2=-1;
while(1){
count1=write(fd1,buf1,strlen(buf1));
if(-1==count1){
perror("buf1->write");
return-1;
}else{
printf("buf1->文件寫入成功\n");
}
sleep(1);
count2=write(fd2,buf2,strlen(buf2));
if(-1==count2){
perror("buf2->write");
return-1;
}else{
printf("buf2->文件寫入成功\n");
}
}
close(fd1);
close(fd2);
return0;
}
在linux系統(tǒng)中,內(nèi)核占用了0、1、2這三個(gè)fd,當(dāng)我們運(yùn)行一個(gè)程序得到一個(gè)進(jìn)程時(shí),內(nèi)部就默認(rèn)已經(jīng)打開了3個(gè)文件,
對(duì)應(yīng)的fd就是0、1、2。分別叫stdin、stdout、stderr。也就是標(biāo)準(zhǔn)輸入、標(biāo)準(zhǔn)輸出、標(biāo)準(zhǔn)錯(cuò)誤。接下來(lái),我們把標(biāo)準(zhǔn)輸出關(guān)閉,printf就不會(huì)輸出,如果用dup復(fù)制原來(lái)的fd,那么新dup出來(lái)的fd就是1(對(duì)應(yīng)標(biāo)準(zhǔn)輸出)
之后標(biāo)準(zhǔn)輸出的內(nèi)容都會(huì)被寫入到原來(lái)fd對(duì)應(yīng)的那個(gè)文件
#include
#include
#include
#include
#include
#include
intmain(intargc,charconst*argv[]){
intfd=-1;
fd=open("ghostwu2.txt",O_RDWR);
if(-1==fd){
perror("open");
return-1;
}else{
printf("文件打開成功fd=%d\n",fd);
}
//fd=0對(duì)應(yīng)stdinfd=1對(duì)應(yīng)stdoutfd=2對(duì)應(yīng)stderror
close(1);//關(guān)閉fd=1的標(biāo)準(zhǔn)輸出之后,printf輸出看不見(jiàn)
intnewFd=-1;
newFd=dup(fd);//newFd一定是1,因?yàn)榉峙浜蟮膄d從最小的沒(méi)被占用的開始
charbuf[3];
sprintf(buf,"%d",newFd);//newFd轉(zhuǎn)字符串型
printf("這是一段輸出,由于newFd和fd關(guān)聯(lián)到標(biāo)準(zhǔn)輸出(newFd=1),會(huì)被寫入到文件\n");
write(fd,buf,1);
return0;
}
以上就是關(guān)于Linux系統(tǒng)編程之簡(jiǎn)單文件IO操作的詳細(xì)介紹,最后想要了解更多關(guān)于Linux發(fā)展前景趨勢(shì),請(qǐng)關(guān)注扣丁學(xué)堂
Linux培訓(xùn)官網(wǎng)、微信等平臺(tái),扣丁學(xué)堂IT職業(yè)在線學(xué)習(xí)教育平臺(tái)為您提供權(quán)威的
Linux視頻教程系統(tǒng),通過(guò)千鋒扣丁學(xué)堂金牌講師在線錄制的第一套自適應(yīng)Linux在線視頻課程系統(tǒng),讓你快速掌握Linux從入門到精通開發(fā)實(shí)戰(zhàn)技能。扣丁學(xué)堂Linux技術(shù)交流群:422345477。
【關(guān)注微信公眾號(hào)獲取更多的學(xué)習(xí)資料】
查看更多關(guān)于“Linux培訓(xùn)資訊”的相關(guān)文章>>
標(biāo)簽:
Linux命令
Linux視頻教程
Linux培訓(xùn)
Linux在線學(xué)習(xí)
Linux在線視頻
Linux系統(tǒng)