C语言:随笔11--文件操作
?文件通常是駐留在外部介質(zhì)(如磁盤等)上的,在使用時(shí)才調(diào)入內(nèi)存中來(lái)。
文件的分類:按數(shù)據(jù)的組織形式:
(1)ASCII文件(文本文件):每一個(gè)字節(jié)放一個(gè)ASCII代碼。
(2)二進(jìn)制文件:把內(nèi)存中的數(shù)據(jù)按其在內(nèi)存中的存儲(chǔ)形式原樣輸出到磁盤上存放。
例如整數(shù)10000D(D表示10進(jìn)制)在內(nèi)存中的存儲(chǔ)形式以及分別按照ASCII形式和二進(jìn)制形式輸出如下圖所示:
ASCII的1對(duì)應(yīng)的十六進(jìn)制是32H(H表示16進(jìn)制),十進(jìn)制是49,二進(jìn)制是110001。
ASCII文件便于對(duì)字符進(jìn)行逐個(gè)處理,也便于輸出字符。但是一般占存儲(chǔ)空間較多,而且要花費(fèi)轉(zhuǎn)換時(shí)間(因?yàn)閮?nèi)存是直接跟CPU交換的,又要用ASCII來(lái)存儲(chǔ),所以二進(jìn)制必須要有一個(gè)轉(zhuǎn)換為ASCII。(因?yàn)镃PU只讀二進(jìn)制))。(比如上邊是一個(gè)字符一個(gè)字符處理的,把1當(dāng)作一個(gè)字符,0當(dāng)作一個(gè)字符,共四個(gè)0分別當(dāng)作4個(gè)字符來(lái)處理)?
二進(jìn)制文件可以節(jié)省外存空間和轉(zhuǎn)換時(shí)間,但是一個(gè)字節(jié)并不對(duì)應(yīng)一個(gè)字符,不能直接輸出字符形式(因?yàn)橐阉D(zhuǎn)化為ASCII再來(lái)輸出)。(因?yàn)槲覀冿@示一個(gè)東西出來(lái)都是按照ASCII碼顯示的,我們輸入一個(gè)東西都是按照ASCII碼形式輸入的,然后它在轉(zhuǎn)化為二進(jìn)制)?
緩沖文件系統(tǒng)和非緩沖文件系統(tǒng)。
C語(yǔ)言對(duì)文件的讀寫都是通過(guò)庫(kù)函數(shù)(緩沖文件系統(tǒng))來(lái)實(shí)現(xiàn)的。
一、文件的打開與關(guān)閉
(1)文件型指針變量
FILE *fp;//FILE是一個(gè)結(jié)構(gòu),是一個(gè)FILE(文件型)結(jié)構(gòu)。FILE是一個(gè)文件的名稱。用這個(gè)結(jié)構(gòu)來(lái)定義一個(gè)指針,這個(gè)指針就是指向一個(gè)文件。//fp是一個(gè)指向FILE類型結(jié)構(gòu)體的指針變量(那么什么是一個(gè)FILE類型結(jié)構(gòu)體呢?)。
FILE類型結(jié)構(gòu)體是定義在我們的標(biāo)準(zhǔn)輸入輸出里面頭文件stdio.h,
??
//先定義一個(gè)input/outputbuffer(緩沖區(qū))結(jié)構(gòu),然后再用typedef類型重命名將iobuf這個(gè)結(jié)構(gòu)命名為FILE。那么我用FILE來(lái)定義一個(gè)fp(FILE *fP;)就相當(dāng)于struct _iobuf *fp;這樣我們的fp指針就指向上邊的結(jié)構(gòu)的。這個(gè)指針我們需要往里邊填充類似于這個(gè)結(jié)構(gòu)的東西。?
我們使fp指向某一個(gè)文件的結(jié)構(gòu)體變量,從而通過(guò)該結(jié)構(gòu)體變量中的文件信息能夠訪問(wèn)該文件。
如果有n個(gè)文件,一般應(yīng)設(shè)n個(gè)指針變量,使他們分別指向n個(gè)文件,以實(shí)現(xiàn)對(duì)文件的訪問(wèn)。
怎么使用呢?我們就可以用FILE類型的數(shù)組:
FILE f[5];定義了一個(gè)結(jié)構(gòu)體數(shù)組f,他有5個(gè)元素,可以用來(lái)存放5個(gè)文件的信息。
(1)文件的打開(fopen函數(shù))
//函數(shù)調(diào)用://定義一個(gè)指向FILE結(jié)構(gòu)體的指針fp
FILE *fp;
fp=fopen(文件名,使用文件方式);//將這個(gè)指針的值賦予什么呢?用fopen打開,其實(shí)用fopen打開他之后它就會(huì)填充這個(gè)結(jié)局體, 然后把他賦給fp,fp指向他。
//注意:(1)需要打開的文件名,也就是準(zhǔn)備訪問(wèn)的文件的名字。(要加上他的路徑是在D盤還是F盤等)
//注意:(2)使用文件的方式(“讀”還是“寫”等)具體的打開方式見(jiàn)下,
//注意:(3)讓哪一個(gè)指針變量指向被打開的文件。(我們這里使用的是fp指向,要保證有指向)
文件的使用方式:
“ab”以這種方式的話打開的時(shí)候指針就是指向了文件的末尾。
對(duì)于文件使用方式有以下說(shuō)明:
- 凡用“r”打開一個(gè)文件時(shí),該文件必須已經(jīng)存在,且只能從該文件讀出。(如果文件不存在就無(wú)法打開,只能返回一個(gè)空指針,NULL指針,就指不到地方去了。)
- 用“w”打開文件只能向該文件寫入。若打開的文件不存在,則以指定的文件名建立該文件。若打開的文件已經(jīng)存在,則該文件刪去,重新建立一個(gè)新文件。
- 若要想一個(gè)已存在的文件追加新的信息,只能用“a”方式打開文件。但此時(shí)該文件必須是存在的,否則將會(huì)出錯(cuò)。
- 在打開一個(gè)文件時(shí),如果出錯(cuò),fopen將返回一個(gè)空指針NULL。在程序中可以用這一信息來(lái)判別是否完成打開文件的工作,并作相應(yīng)的處理。
- 把一個(gè)文本文件讀入內(nèi)存時(shí),要將ASCII碼轉(zhuǎn)換成二進(jìn)制碼,而把文件以文本方式寫入磁盤時(shí),也要把二進(jìn)制碼轉(zhuǎn)換成ASCII碼,因此文本文件的讀寫要花費(fèi)較多的轉(zhuǎn)換時(shí)間。對(duì)二進(jìn)制文件的讀寫不存在這種轉(zhuǎn)換。
示例代碼:
#include<stdio.h>
#include<stdlib.h>
void main()
{FILE *fp;if(!(fp=fopen("F:\\1.txt","rb")))//注意要“\” //b是二進(jìn)制的形式{printf("Can not open F:\\1 file!\n");system("pause");//讓系統(tǒng)暫停在這,接受用戶的操作}else{printf("Open success!\n");}
}
(2)文件的關(guān)閉
文件只要打開了他就要映射到內(nèi)存上去了,那如果我沒(méi)沒(méi)有把他給關(guān)閉,沒(méi)有把這個(gè)指針給斷開的話,它會(huì)一直占著那個(gè)空間。
?
//函數(shù)調(diào)用:
fclose(文件指針);
//函數(shù)功能:使文件指針變量不再指向該文件,也就是文件指針變量與文件“脫鉤”,此后不餓能再通過(guò)該指針對(duì)原來(lái)與其相聯(lián)系的文件進(jìn)行讀寫操作。
//返回值:關(guān)閉成功返回值為0;否則返回EOF在C語(yǔ)言中定義為-1.
讀就是把文件的內(nèi)容讀出來(lái),讀取到緩沖區(qū)。寫就是把新的內(nèi)容寫入文件中。
C中有多種的文件讀寫函數(shù):
//字符讀寫函數(shù):fgetc和fputc//其中f是file的縮寫,c是char的縮寫
//字符串讀寫函數(shù):fgets和fputs 。
//數(shù)據(jù)塊讀寫函數(shù):freed和fwrite。
//格式化讀寫函數(shù):fscanf和fprintf//就是按照一定的格式,有點(diǎn)像我們的scdnf和printf,前邊加上f表示他是關(guān)于文件的。
//以上函數(shù)都要包含頭文件stdio.h。
(1)字符輸入輸出函數(shù)(fputc()和fgetc())
//fputc()函數(shù)調(diào)用:
fputc(ch,fp);//fp是一個(gè)指針
//函數(shù)功能:將字符(ch的值)輸出到fp所指向的文件中去。(比如字符‘a(chǎn)’他的ASCII碼是65,那就把65輸入進(jìn)去,因?yàn)槲覀兪羌兾谋据斎?#xff0c;是輸入ASCII的)
//用寫或者讀寫方式打開一個(gè)已存在的文件時(shí)將清除原有的文件內(nèi)容,寫入字符從文件首開始。如需保留原有文件內(nèi)容,希望寫入的字符以文件末開始存放,必須以追加方式打開文件。被寫入的文件若不存在,則創(chuàng)建該文件。
//每寫入一個(gè)字符,文件內(nèi)部位置指針向后移動(dòng)一個(gè)字節(jié)。
//fputc函數(shù)有一個(gè)返回值,如寫入成功則返回寫入的字符,否則返回一個(gè)EOF。可以用來(lái)判斷寫入是否成功。//示例文件的寫入:
#include<stdio.h>
#include<stdlib.h>
void main()
{ FILE *fp;//指針fp指向FILE結(jié)構(gòu),也就是說(shuō)指針指向的內(nèi)存它是以FILE結(jié)構(gòu)來(lái)讀取的char ch,filename[20];printf("Please input the filename you want to write:");scanf("%s",filename);//filename是數(shù)組名表示首地址//表示將要?jiǎng)?chuàng)建的文件的名稱if(!(fp=fopen(filename,"wt+")));//wt+表示讀寫打開或建立一個(gè)文本文件,允許讀和寫{//打開錯(cuò)誤就是返回NULL,那么!NULL就是1,進(jìn)入if語(yǔ)句,輸出不能打開文件printf("Cannot open the file!\n");exit(0);//終止程序}printf("Please input the sentences you want to write:");ch=getchar();ch=getchar();//有兩個(gè)getchar()函數(shù)?(如果只寫一個(gè)ch=getchar();語(yǔ)句寫入的文件就會(huì)在內(nèi)部的一行出現(xiàn)一個(gè)空行?為什么?)while(ch!=EOF)//如果輸入的不是EOF //EOF一般是我們ASCII編碼的文件的結(jié)束標(biāo)志,怎么輸入EOF呢?(EOF輸入是ctl+z組合鍵){fputc(ch,fp);ch=getchar();//再次接收來(lái)自鍵盤的輸入,然后繼續(xù)循環(huán)把他給寫入,直到我們輸入EOF}fclose(fp);//關(guān)掉文件
}
//fgetc()函數(shù)調(diào)用:
ch=fgetc(fp);
//函數(shù)功能:其意義是從打開的文件fp中讀取一個(gè)字符并送入ch中。
//在fgetc函數(shù)調(diào)用中,讀取的文件必須是以讀或讀寫方式打開。
//在文件內(nèi)部有一個(gè)位置指針。用來(lái)指向文件當(dāng)前讀寫子節(jié)。(因?yàn)槲覀冏x取一個(gè)之后等一下要讀取第二個(gè),指針要指向第二個(gè)你才能讀取,如果一直指向第一個(gè)的話你就只能永遠(yuǎn)讀取的第一個(gè)。所以有一個(gè)指針你讀了第一個(gè)之后他會(huì)自動(dòng)指向第二個(gè)。有一個(gè)這樣的機(jī)制 )
//在文件打開時(shí),該文件總是指向文件的第一個(gè)子節(jié)。使用fgetc函數(shù)后,該位置指針將向后移動(dòng)一個(gè)字節(jié)。因此連續(xù)多次使用fgetc函數(shù),讀取多個(gè)字符。
//應(yīng)注意文件指針(FILE *fp)和文件內(nèi)部的位置指針(是windows系統(tǒng)內(nèi)部自動(dòng)匹配自動(dòng)調(diào)用的我們不需要管)不是一回事。
//文件指針是指向整個(gè)文件的,須在程序中定義說(shuō)明,只要不重新賦值,文件指針的值是不變的。
//文件內(nèi)部的位置指針用以指示文件內(nèi)部的當(dāng)前讀寫位置,每讀寫一次,該指針均向后移動(dòng),它不需要在程序中定義說(shuō)明,而是由系統(tǒng)自動(dòng)設(shè)置的。 //示例文件的寫入:
#include<stdio.h>
#include<stdlib.h>
void main()
{ FILE *fp;//指針fp指向FILE結(jié)構(gòu),也就是說(shuō)指針指向的內(nèi)存它是以FILE結(jié)構(gòu)來(lái)讀取的char ch,filename[20];printf("Please input the filename you want to write:");scanf("%s",filename);//filename是數(shù)組名表示首地址//表示將要?jiǎng)?chuàng)建的文件的名稱if(!(fp=fopen(filename,"r")));{printf("Cannot open the file!\n");exit(0);//終止程序}while(ch!=EOF){ch=fgetc(fp);//讀出的字符保存在ch中putchar(ch);//把ch顯示在屏幕上 }fclose(fp);//關(guān)掉文件
}//補(bǔ)充1 :
//從一個(gè)文本文件順序讀入字符并顯示在屏幕上。
ch=fgetc(fp);
while(ch!=EOF)
{putchar(ch);ch=fgetc(fp);
}
//注意:EOF不是可輸出字符,因此不能在屏幕上顯示。由于字符的ASCII碼不可能出現(xiàn)-1(ASCII碼是從0開始),因此EOF定義為-1是合適的。當(dāng)讀入的字符值等于-1時(shí),表示讀入的已不是正常的字符而是文件結(jié)束符。
//補(bǔ)充2:
//從一個(gè)二進(jìn)制文件順序讀入字符 ;(就不是-1的問(wèn)題了,因?yàn)槎M(jìn)制文件你想什么數(shù)都可以,因?yàn)镃PU處理的是二進(jìn)制文件,沒(méi)有任何約定,任何數(shù)都是二進(jìn)制文件,那么它就沒(méi)有一個(gè)EOF我們可以定了,那么我們?cè)趺粗浪Y(jié)束了呢?我們用一個(gè)函數(shù)feof(),eof就是end of file的縮寫,feof()是文件結(jié)束的一個(gè)函數(shù))
while(!feof(fp))//feof()函數(shù)作用:Tests for end-of-file on a stream.測(cè)試是否文件的結(jié)尾
{ch=fget(fp);
}
//因此ANSIC提供一個(gè)feof()函數(shù)來(lái)判斷文件是否真的結(jié)束。如果文件結(jié)束,函數(shù)feof(fp)的值為1(真);否則為0(假)。這個(gè)也適用于文本文件的讀取。//但是在二進(jìn)制文件中不能使用EOF(因?yàn)槎M(jìn)制文件中有-1這個(gè)數(shù))。
編寫一個(gè)二進(jìn)制文件的讀取和寫入:(圖片、文件合成器)
在圖片捆綁了一個(gè)可執(zhí)行文件(.rar)(一個(gè)jpg圖片更改后綴名為rar,就會(huì)生成一個(gè)壓縮文件。將一個(gè)jpg圖片加進(jìn)來(lái)一個(gè).rar文件,是兩者的合成版本 )
#include<stdio.h>
#include<stdlib.h>
void main()
{FILE *f_pic,*f_file,*f_finish;//需要三個(gè)指針文件,打開兩個(gè),再寫入一個(gè)新的char ch,pic_name[20],file_name[20],finish_name[20]; //聲明變量printf("請(qǐng)輸入需要合成的圖片和文件名稱:\n");printf("圖片:");scanf("%s",pic_name);//w文件的名稱是什么?字符串,必須把它把他賦值到一個(gè)變量里邊去。//所以上邊要聲明變量printf("文件:");scanf("%s",file_name);printf("生成為:");scanf("%s",finish_name);//打開pic1if(!(f_pic=fopen(pic_name,"rb")))//以二進(jìn)制讀寫方式打開,并存放在f_pic這個(gè)文件指針里{printf("Cannot open the picture %s",pic_name);//打不開return;}//打開file2if(!(f_file=fopen(file_name,"rb")))//以二進(jìn)制讀寫方式打開,并存放在f_pic這個(gè)文件指針里{printf("Cannot open the picture %s",file_name);//打不開return;}//打開3第三個(gè)是要寫入的,是原本不存在的,我們新建的。//我們將要生成的if(!(f_finish=fopen(finish_name,"wb")))//以二進(jìn)制讀寫方式打開,并存放在f_pic這個(gè)文件指針里{printf("Cannot open the file %s",finish_name);//打不開 return;}//先把打開的1讀出來(lái)然后寫進(jìn)3。寫完之后再把2的內(nèi)容寫進(jìn)3.//我們要寫一個(gè)文件,必須要判斷文件內(nèi)部指針有沒(méi)有指向結(jié)尾,才知道什么時(shí)間結(jié)束,所以使用內(nèi)置函數(shù)feof()//函數(shù)返回值如果返回0表示現(xiàn)在的位置不是文件尾部,返回非0說(shuō)明是文件的結(jié)尾了。while(!feof(f_pic)){ch=fgetc(f_pic);//上邊定義的ch是用來(lái)暫時(shí)存放讀取的那個(gè)數(shù)據(jù)//fgetc()這個(gè)函數(shù)就會(huì)讀取f_pic這個(gè)文件里面的一個(gè)字節(jié),然后把他當(dāng)作返回值賦值給ch.fputc(ch,f_finish); //然后將ch給了finish_name這個(gè)文件.(參數(shù)1:需要寫入的字符;參數(shù)2:需要寫入的文件的指針)}//進(jìn)行到文件尾部就會(huì)退出while,所以我們要關(guān)掉這個(gè)文件指針fclose(f_pic);//現(xiàn)在把壓縮文件接到后邊去(當(dāng)要接一個(gè)文件后邊繼續(xù)添加內(nèi)容時(shí):(就比如上邊已經(jīng)拷貝進(jìn)去一個(gè)了要接著在文件中在后邊再添加一個(gè))這時(shí)這里的文件內(nèi)部指針不用去管它,當(dāng)他拷貝到文件后面呢最后一個(gè)位置時(shí)他的指針現(xiàn)在是指向文件最后一個(gè)格的(也就是最后一個(gè)字節(jié)的))while(!feof(f_file)){ch=fgetc(f_file);//上邊定義的ch是用來(lái)暫時(shí)存放讀取的那個(gè)數(shù)據(jù)//fgetc()這個(gè)函數(shù)就會(huì)讀取f_pic這個(gè)文件里面的一個(gè)字節(jié),然后把他當(dāng)作返回值賦值給ch.fputc(ch,f_finish); //然后將ch給了finish_name這個(gè)文件.(參數(shù)1:需要寫入的字符;參數(shù)2:需要寫入的文件的指針)}//進(jìn)行到文件尾部就會(huì)退出while,所以我們要關(guān)掉這個(gè)文件指針fclose(f_file);fclose(f_finish);//都關(guān)掉system("pause");}
-----上邊是一個(gè)個(gè)字節(jié)讀取現(xiàn)在字符串的讀寫函數(shù):fgets和fputs
字符串的輸入輸出函數(shù)fputs()和fgets()。
//fgets()函數(shù)
//函數(shù)調(diào)用形式如:fgets(str,n,fp);//有三個(gè)參數(shù)
//函數(shù)作用:從fp所指的文件中讀出n-1個(gè)字符送入字符數(shù)組str中,因?yàn)樵谧詈蠹右粋€(gè)'\0'(字符串的標(biāo)志結(jié)尾0,C語(yǔ)言規(guī)定字符串的結(jié)尾是以\0來(lái)標(biāo)志的,其他語(yǔ)言有所不同).
//函數(shù)返回值:返回str的首地址。
讀出示例:
//有一個(gè)1.txt文件,我想把它讀出來(lái),然后打印到屏幕上
#include<stdio.h>
#include<stdlib.h>
#define LEN 11//用宏定義方便后期改字節(jié),不用一個(gè)個(gè)去改
void main()
{FILE *fp;char buffer[LEN];//定義一個(gè)字符緩沖區(qū),該字符緩沖區(qū)有LEN這么長(zhǎng),也就是下邊可以讀取LEN-1個(gè)字節(jié),因?yàn)樽詈笠粋€(gè)字節(jié)他會(huì)自動(dòng)加上‘\0’,表示字符串結(jié)束。if(!fp=fopen("1.txt","rt"))//fp指向的是1.txt這個(gè)文件 {printf("\nCannot open file strike any key exit!");exit(1);}fgets(buffer,LEN,fp);//從fp拿到LEN-1這么長(zhǎng)的東西,給了buffer這個(gè)緩沖區(qū)printf("%s\n",buffer);//把buffer緩沖區(qū)的內(nèi)容以字符串的形式打印出來(lái) fclose(fp);//關(guān)閉}
fputs()字符串的寫入一個(gè)文件:
//fputs函數(shù)
//函數(shù)調(diào)用方式:fputs("FISHC",fp);//將FISHC輸入到我們fp所指向的這個(gè)文件中
//函數(shù)作用:把字符串"FISHC"寫入fp所指的文件之中。
//函數(shù)返回值:輸入成功的話,返回值為0;輸入失敗的話,返回值時(shí)EOF。
寫入函數(shù)示例:
//從屏幕上輸入一個(gè)字符串,然后程序截取這個(gè)字符串,把他給放到這個(gè)文件的結(jié)尾處
#include<stdio.h>
#include<stdlib.h>
#define LEN 20
void main()
{FILE *fp;char ch,buffer[LEN];//建立20個(gè)長(zhǎng)度的緩沖區(qū)用來(lái)放入從屏幕上輸入的字符串if(!fp=fopen("1.txt","at+"))//這里以“at+”的形式寫入,粘貼在后面(意思就是將1.txt這個(gè)文件打開,將內(nèi)部的文件指針指向了結(jié)尾處,然后我們從這里寫入的話是從文件的結(jié)尾開始寫){printf("\nCannot open file strike any key exit!");exit(1);}printf("Please input a string:\n",buffer);//正常做法輸入字符串用scanf()//scanf("%s",buffer);//接收一個(gè)字符串,然后把他存在buffer這個(gè)緩沖區(qū)里面//因?yàn)閟canf這個(gè)函數(shù)使用%s接收字符串的話,當(dāng)他遇到空格和回車的時(shí)候,他都是自動(dòng)聲明這個(gè)接收已經(jīng)結(jié)束了,后邊的就不再接收了。//前邊講過(guò)fgets()是從文件中獲取字符串,那為什么這里可以從我們的鍵盤獲取?(因?yàn)槲覀兊逆I盤實(shí)際上也是夜歌特殊的文件,叫做stdin文件,標(biāo)準(zhǔn)輸入文件,我們從鍵盤上輸入的東西會(huì)放入stdin這個(gè)文件,作為一個(gè)緩沖區(qū)存放到里面去,那么我們就從stdin這里面讀就可以了)fgets(buffer,LEN,stdin);//寫入的話用fgets()來(lái)寫,而不用scanf().//為什么不用scanf()?stdin又是啥?fputs(buffer,fp);//把buffer寫入到fp這個(gè)文件里面去(fputc如果是c的話參數(shù)Buffer就得表示一個(gè)字節(jié),fputs如果是s的話參數(shù)buffer就得是一個(gè)字符串,但是fp都是一個(gè)指向的文件。)rewind(fp);//(寫完之后)重新定義文件內(nèi)部指針去指向到開頭處(這樣是比較優(yōu)良的做法,不這樣做也沒(méi)問(wèn)題)(這里之所以這么做,因?yàn)槲疫€想把他再打印出來(lái),這樣可以讓我們看到整個(gè)文件寫進(jìn)去之后有所改變)ch=fgetc(fp);while(ch!=EOF)//這里使用一個(gè)循環(huán),只要他不是文件結(jié)尾他就會(huì)把它輸出到屏幕上{putchar(ch);ch=fgetc(fp);}printf("\n");fclose(fp);//關(guān)閉}
數(shù)據(jù)塊讀寫函數(shù)fread()和fwrite()。//可以使用fread和fwrite來(lái)進(jìn)行數(shù)據(jù)的操作。
什么是數(shù)據(jù)塊呢?剛才是一串一串的讀,我們現(xiàn)在是一塊一塊的讀。
//函數(shù)調(diào)用:
//fread(buffer,size,count,fp);
//fwrite(buffer,size,coubt,fp);
//參數(shù)說(shuō)明:
//buffer:是一個(gè)指針。(對(duì)fread來(lái)說(shuō),他是一個(gè)讀入數(shù)據(jù)的存放地址;對(duì)fwrite來(lái)說(shuō),是要輸出數(shù)據(jù)的地址(均指起始地址))(是一個(gè)緩沖區(qū))
//size要讀寫的字節(jié)數(shù)。(這個(gè)塊非常靈活,你可以當(dāng)他是一個(gè)字節(jié)一個(gè)字節(jié)或者10個(gè)字節(jié)一個(gè)塊也行)
//count:要進(jìn)行讀寫多少個(gè)size字節(jié)的數(shù)據(jù)項(xiàng)。(次數(shù)/個(gè)數(shù)。比如我的size是10個(gè)字節(jié),count是2,那就是你讀取了20個(gè)字節(jié)。(就是以10個(gè)字節(jié)分為1塊,讀取count2個(gè)塊))
//fp:是一個(gè)文件的指針。
示例:如下結(jié)構(gòu):
struct student_type
{ char name[20]; int num;int age;char addr[30];
}stud[40];//定義了40個(gè)學(xué)生,每個(gè)學(xué)生都是一個(gè)這樣的結(jié)構(gòu)//讀取方式
for(I=0;i<40;i++)
{fread(&stud[i],sizeof(struct student_type),1,fp);//聲明要讀取到std這個(gè)變量里邊去,每次讀取的大小是sizeof,每次讀一次就是一個(gè)學(xué)生,從fp這個(gè)文件
}
//寫入也一樣每次寫入一個(gè)學(xué)生的內(nèi)容(你如果按照原來(lái)一個(gè)字節(jié)一個(gè)字節(jié)的來(lái)寫,那么各個(gè)學(xué)生就會(huì)打亂了)
for(I=0;i<40,i++)
{fwrite(&stud[i],sizeof(struct student-type),1,fp);
}
要求:從鍵盤輸入4個(gè)學(xué)生的有關(guān)數(shù)據(jù),然后以二進(jìn)制的格式存儲(chǔ)到磁盤文件。
#include<stdio.h>
#include<stdlib.h>
define SIZE 4;
struct student
{char name[10]; int num;int age;char addr[15];
}stu[SIZE];
void save()
{FILE *fp;int i;if(!(fp=fopen("student-list","wb")))//student-list是一個(gè)二進(jìn)制文件{printf("Cannot open the file!\n"); return; }for(i=0;i<size;i++){if(fwrite(&stu[i],sizeof(struct studet),1,fp)!=1){printf("File write error!\n");fclose(fp);}}
}
//寫一個(gè)load()函數(shù)將該文件讀取并顯示
void load()
{FILE *fp;int i;if(!(fp=fopen("student-list","r")))//student-list是一個(gè)二進(jìn)制文件{printf("Cannot open the file!\n"); return; }//讀取方式for(i=0;i<40;i++){fread(&stud[i],sizeof(struct student),1,fp);//printf("%s,%d,%d,%s",&stud[i].name,&stud[i].num,&stud[i].age,&stud[i].address);//不需要這一行(因?yàn)閒read帶顯示)fclose(fp);}
void main()
{ int i;printf("Please input student's name,num,age,address:\n");for(i=0;i<40,i++){scanf("%s %d %d %s",stud[i].name,&stud[i].num,&stud[i].age,&stud[i].address); }//此時(shí)輸入的都是輸入到緩沖區(qū)文件里邊去save();load();
}
-----格式化讀寫函數(shù)(fprintf()和fscanf())//(跟平時(shí)使用的printf和scanf是一樣的,前邊多了一個(gè)f表示是對(duì)文件的讀寫)(如果沒(méi)有f的話它是對(duì)我們的鍵盤還有顯示器,寫入/寫進(jìn)到顯示器就是輸出數(shù)來(lái),從鍵盤上讀取字符。)
//函數(shù)調(diào)用:
//fprintf(文件指針,格式字符串,輸出表列);
//fscanf(文件指針,格式字符串,輸出表列);
//函數(shù)功能:從磁盤文件中按照格式讀入或輸出字符。
//例如:
//fprintf(fp,"%d,%6.2f",i,t);// “%6.2f”表示6位的浮點(diǎn)數(shù),兩位的小數(shù)點(diǎn),然后存放在這個(gè)t這個(gè)浮點(diǎn)型的變量里面。
//fscanf(fp,"%d,%f",&i,&t);
-----順序讀寫和隨機(jī)讀寫
順序讀寫:以上將的都是順序讀寫(就是從文件打開,從頭開始往后這么寫進(jìn)去/或者讀出來(lái) )
位置指針按字節(jié)位置順序移動(dòng)。
隨機(jī)讀寫:讀寫完一個(gè)字符(字節(jié))后,并不一定要讀寫其后續(xù)的字符(字節(jié)),而可以讀寫文件中任意位置上所需要的字符(字節(jié))(這個(gè)位置我們是可以控制它的,那么我們就必須要學(xué)一個(gè)fseek函數(shù))
fseek函數(shù)(一般用于二進(jìn)制的文件比較多)(作用是改變文件的位置指針)
//函數(shù)功能:
//改變文件的位置指針(這個(gè)函數(shù)主要是改變文件內(nèi)部的指針,改變它我們就可以跳躍性的讀寫,比如說(shuō)讀了第一個(gè)字符之后我就用fseek把他跳躍到第以00個(gè)字符,之后我就從第100個(gè)字符開始讀了)
//函數(shù)調(diào)用格式:
//fseek(文件類型指針,位移量,起始點(diǎn));
//第三個(gè)參數(shù):起始點(diǎn):
//文件開頭 SEEK_SET 0//如果起始點(diǎn)設(shè)置的是0的話,他的宏定義是SEEK_SET,他是從文件的開頭位置開始讀的
//文件當(dāng)前位置 SEEK_CUR 1//如果起始位置設(shè)為1的話他是從文件的當(dāng)前的文件指針的位置,因?yàn)槲覀兠孔x過(guò)一次,他的文件指針都會(huì)向后移一格
//文件末尾 SEEK_END 2//如果是2的話,宏定義是SEEK_END的話,他是標(biāo)志著從文件的末尾開始讀取
//第二個(gè)參數(shù):位移量
//位移量:以起始點(diǎn)為基點(diǎn),向前移動(dòng)的字節(jié)數(shù)(以這個(gè)起始點(diǎn)標(biāo)志的位置以后的偏移量等于多少,就是這個(gè)位移量一般都是以long型的形式存在的)
//例如:fseek(fp,100L,0);//將位置指針移到離文件頭100格字節(jié)處//L表示long型
//fseek(fp,50L,1);//將位置指針移到離當(dāng)前位置50個(gè)字節(jié)處(這個(gè)當(dāng)前位置就不一定是文件頭了,說(shuō)不定在之前已經(jīng)read過(guò)多少次了,讀過(guò)多少個(gè)字節(jié)了,那就從你現(xiàn)在接著的地方開始,50個(gè)字節(jié)處)
//fseek(fp,50L,2);//將文件指針從文件末尾處向后退50個(gè)字節(jié)(因?yàn)橐呀?jīng)是最末尾了,不能再前進(jìn)了,所以表示向后退)
//fseek(fp,i*sizeof(struct stu),0)//這樣的話我們就要通過(guò)表達(dá)式計(jì)算了,i是個(gè)變量
例子:在學(xué)生文件stu_list中讀出第二個(gè)學(xué)生的數(shù)據(jù)
struct student
{char name[10];int num;int age;char addr[15];
}boy;//student結(jié)構(gòu)中的Boy變量
void main()
{FILE *fp;int i;//用于定位i個(gè)結(jié)構(gòu)if(!(fp=fopen(student_list,"r"))){printf("Cannot open the file!\n");return;}rewind(fp);//設(shè)置內(nèi)部文件指針指向頭(也就是重置了文件指針)fseek(fp,i*sizeof(struct student),0);//這個(gè)時(shí)候文件內(nèi)部指針已經(jīng)指向了第二個(gè)學(xué)生的開頭位置fread(&boy,sizeof(struct student),1,fp);//&boy第一個(gè)傳給他緩沖區(qū)就是存放的一個(gè)地址。然后sizeof(struct student)存放多少(一塊讀取多少),1讀取一塊就行了,fp指向文件printf("name\tnumber age addr\n");//打印出來(lái)printf("%s\t%5d %7d %s\n",boy.name,boy.num,boy.age,boy.addr);fclose(fp);system("pause");
}
ftell函數(shù)
//函數(shù)作用:得到流式文件(就是我們的文件流)中當(dāng)前位置,用相對(duì)于文件開頭的位移量來(lái)表示。
//返回值:返回當(dāng)前位置(就是當(dāng)前位置離文件開頭的偏移量),出錯(cuò)時(shí)返回-1L,在文件頭就是返回0,在文件頭一個(gè)字節(jié)的地方他就是返回1。
//應(yīng)用舉例;
i=ftell(fp);
if(i==-1L)
{printf("erroe\n");
}
---出錯(cuò)的檢測(cè)ferror函數(shù)(對(duì)于檢測(cè)輸入輸出會(huì)不會(huì)出現(xiàn)錯(cuò)誤)
//ferror函數(shù)
//調(diào)用形式:
ferror(fp);
//返回值:返回0,表示未出錯(cuò);返回非0,表示出錯(cuò)。
//注意:在調(diào)用一個(gè)輸入輸出函數(shù)后立即檢查ferror函數(shù)的值,否則信息會(huì)丟失(就是會(huì)被下一個(gè)覆蓋掉)。再指向fopen函數(shù)時(shí),ferror函數(shù)的初始值自動(dòng)置為0(因?yàn)閯倓偞蜷_,打開成功的話初始值是設(shè)為0的)。
?----clearerr函數(shù)
//調(diào)用形式:
clearer(fp);
//函數(shù)作用:使文件錯(cuò)誤標(biāo)志和文件結(jié)束標(biāo)志置為0.
//注意:只要出現(xiàn)錯(cuò)誤標(biāo)志,就一直保留,直到對(duì)同一文件調(diào)用clearerr函數(shù)或rewind函數(shù),或任何其他一個(gè)輸入輸出函數(shù)。
總結(jié):
? ?
?
?
總結(jié)
以上是生活随笔為你收集整理的C语言:随笔11--文件操作的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: C语言:随笔10--共用体
- 下一篇: ladar:16线激光雷达(雷神)