語(yǔ)言中對(duì)文件進(jìn)行操作必須首先打開(kāi)文件,打開(kāi)文件主要涉及到fopen函數(shù)。fopen函數(shù)的原型為
FILE* fopen(const char *path,const char *mode)
其中path為文件路徑,mode為打開(kāi)方式
1)對(duì)于文件路徑,只需注意若未明確給出絕對(duì)路徑,則默認(rèn)該文件在工程的目錄下。若需給出絕對(duì)路徑,則注意轉(zhuǎn)義字符'\\',比如有文件test.txt存放在C盤根目錄下,則文件路徑參數(shù)值應(yīng)為C:\\\\test.txt。
2)對(duì)于mode,主要由r,w,a,+,b,t六個(gè)字符組合而成。
r:只讀方式,文件必須存在
w:只寫方式,若文件存在,則原有內(nèi)容會(huì)被清除;若文件不存在,則會(huì)建立文件
a:追加方式打開(kāi)只寫文件,只允許進(jìn)行寫操作,若文件存在,則添加的內(nèi)容放在文件末尾;若不存在,則建立文件
+:可讀可寫
b:以二進(jìn)制方式打開(kāi)文件
t:以文本方式打開(kāi)文件(默認(rèn)方式下以文本方式打開(kāi)文件)
下面是常見(jiàn)的組合:
r: ? ? ?以只讀的方式打開(kāi)文件,只允許讀,此文件必須存在,否則返回NULL,打開(kāi)成功后返回文件指針,位置指針指向文件頭部
r+: ? ?以可讀可寫的方式打開(kāi)文件,允許讀寫,此文件必須存在,否則返回NULL,打開(kāi)成功后返回文件指針,位置指針指向文件頭部
rb+: ?以可讀可寫、二進(jìn)制方式打開(kāi)文件,允許讀寫,此文件必須存在,否則返回NULL,打開(kāi)成功后返回文件指針,位置指針指向文件頭部
rt+: ?以可讀可寫、文本方式打開(kāi)文件,允許讀寫,此文件必須存在,否則返回NULL,打開(kāi)成功后返回文件指針,位置指針指向文件頭部
w: ? ?以只寫的方式打開(kāi)文件,只允許寫,若文件存在,文件中原有內(nèi)容會(huì)被清除;若文件不存在,則創(chuàng)建文件,打開(kāi)成功后返回文件指針,位置指針指向文件頭部
w+: ?以讀寫的方式打開(kāi)文件,允許讀寫,若文件存在,文件中原有內(nèi)容會(huì)被清除;若文件不存在,則創(chuàng)建文件,打開(kāi)成功后返回文件指針,位置指針指向文件頭部
a: ? ? 以追加、只寫的方式打開(kāi)文件,只允許寫。若文件存在,則追加的內(nèi)容添加在文件末尾,若文件不存在,則創(chuàng)建文件。打開(kāi)成功后返回文件指針,位置指針指向文件頭部(注意很多書(shū)上或資料上講述追加方式打開(kāi)成功后位置指針指向文件末尾是錯(cuò)誤的)
a+: ? 以追加、可讀寫的方式打開(kāi)文件,允許讀寫。若進(jìn)行讀操作,則從頭開(kāi)始讀;若進(jìn)行寫操作,則將內(nèi)容添加在末尾。若文件不存在,則創(chuàng)建文件。打開(kāi)成功后返回文件指針,位置指針指向文件頭部。
其他方式類似。
下面討論一下以二進(jìn)制方式和文本方式打開(kāi)文件有什么區(qū)別。
其實(shí)這兩種方式打開(kāi)文件并沒(méi)有太大的區(qū)別,僅僅只有一點(diǎn)區(qū)別就是在處理某些特殊字符的時(shí)候。
以文本方式打開(kāi)文件,若將數(shù)據(jù)寫入文件,如果遇到換行符'\\n'(ASII
值為10,0A),則會(huì)轉(zhuǎn)換為回車—換行'\\r\\n'(ASII值為13,10,0D0A)存入到文件中,同樣讀取的時(shí)候,若遇到回車—換行,即連續(xù)的
ASII值13,10,則自動(dòng)轉(zhuǎn)換為換行符。
而以二進(jìn)制方式打開(kāi)文件時(shí),不會(huì)進(jìn)行這樣的處理。
還有如果以文本方式打開(kāi)文件時(shí),若讀取到ASCII碼為26(^Z)的字符,則停止對(duì)文件的讀取,會(huì)默認(rèn)為文件已結(jié)束,而以二進(jìn)制方式讀取時(shí)不會(huì)發(fā)生這樣
的情況。由于正常情況下我們手動(dòng)編輯完成的文件是不可能出現(xiàn)ASCII碼為26的字符,所以可以用feof函數(shù)去檢測(cè)文件是否結(jié)束。以上所述的兩點(diǎn)區(qū)別只
在windows下存在,在unix下沒(méi)有區(qū)別。
注意:1)在以追加方式打開(kāi)文件時(shí),位置指針指向文件的首部。
在這里區(qū)分一下位置指針和文件指針:
文件指針:指向存儲(chǔ)文件信息的一個(gè)結(jié)構(gòu)體的指針
位置指針:對(duì)文件進(jìn)行讀寫操作時(shí)移動(dòng)的指針
在頭文件中存在一個(gè)結(jié)構(gòu)體_iobuf,在VC6.0中選中FILE,然后F12,則可以看到_iobuf的具體定義:

struct_iobuf {
char*_ptr;
int_cnt;
char*_base;
int_flag;
int_file;
int_charbuf;
int_bufsiz;
char*_tmpfname;
};
typedefstruct_iobuf FILE;

比如用FILE *fp定義了一個(gè)文件指針,并成功打開(kāi)一個(gè)文件之后,fp只是指向該結(jié)構(gòu)體,而在對(duì)文件進(jìn)行讀寫操作時(shí),fp的值并不會(huì)改變,改變的是結(jié)構(gòu)體中_ptr的值,這個(gè)_ptr就是位置指針。
2)以追加方式打開(kāi)時(shí),若進(jìn)行寫操作,則rewind函數(shù)和fseek函數(shù)不會(huì)起到作用,因?yàn)橐宰芳臃绞酱蜷_(kāi)時(shí)進(jìn)行寫操作的話,系統(tǒng)會(huì)自動(dòng)將位置指針移動(dòng)到末尾。
3)當(dāng)文件打開(kāi)用于更新時(shí),可以通過(guò)文件指針對(duì)文件進(jìn)行讀寫操作,但是如果沒(méi)有給出fseek或者rewind的話,讀操作后面不能直接跟寫操作,否則會(huì)是無(wú)效的寫操作(位置指針會(huì)移動(dòng),但是需要寫入文件的內(nèi)容不會(huì)被寫入到文件當(dāng)中),但是寫操作后可以直接跟讀操作。
1.測(cè)試程序
假設(shè)工程目錄下已存在文件test.txt,文件中含有的字符串為"ABC"

/*測(cè)試fopen函數(shù)以追加方式打開(kāi)文件時(shí)初始指針的位置 2011.10.5*/
#include
#include
intmain(void)
{
intn;
FILE *fp;
if((fp=fopen("test.txt","a"))==NULL)
{
printf("can not open file\\n");
exit(0);
}
n=ftell(fp);//得到此時(shí)fp所處位置距文件首的偏移字節(jié)數(shù)
printf("%d\\n",n);
fputs("test",fp);
n=ftell(fp);
printf("%d\\n",n);
fclose(fp);
return0;
}

輸出結(jié)果為:
0
7
Press any key to continue
由輸出結(jié)果可知,初始打開(kāi)文件后,指針是位于文件首部,只是在往文件中添加內(nèi)容時(shí),才將文件指針移動(dòng)到文件末尾。
2.測(cè)試程序

/*測(cè)試以二進(jìn)制方式和文本方式打開(kāi)文件的區(qū)別 2011.10.5*/
#include
#include
intmain(void)
{
charch;
inti;
chars[]={'A','B','\\n','C'};
FILE *fp1,*fp2;
if((fp1=fopen("test1.txt","wt"))==NULL)
{
printf("can not open file\\n");
exit(0);
}
if((fp2=fopen("test2.txt","wb"))==NULL)
{
printf("can not open file\\n");
exit(0);
}
for(i=0;i<4;i++)
{
fputc(s[i],fp1);//以文本方式向文件中寫入數(shù)據(jù)
fputc(s[i],fp2);//以二進(jìn)制方式向文件中寫入數(shù)據(jù)
}
fclose(fp1);
fclose(fp2);
if((fp1=fopen("test1.txt","rt"))==NULL)
{
printf("can not open file\\n");
exit(0);
}
if((fp2=fopen("test1.txt","rb"))==NULL)
{
printf("can not open file\\n");
exit(0);
}
ch=fgetc(fp1);
while(!feof(fp1))//以文本方式從文件中讀取數(shù)據(jù)
{
printf("%02X",ch);
ch=fgetc(fp1);
}
printf("\\n");
ch=fgetc(fp2);
while(!feof(fp2))//以二進(jìn)制方式從文件中讀取數(shù)據(jù)
{
printf("%02X",ch);
ch=fgetc(fp2);
}
printf("\\n");
fclose(fp1);
fclose(fp2);
return0;
}

在向文件中寫完數(shù)據(jù)后,用UltraEdit以二進(jìn)制方式打開(kāi)test1.txt和test2.txt,看到的結(jié)果如下:


根據(jù)得到的結(jié)果可知,以文本方式寫入時(shí),多寫入了一個(gè)字符0D,即'\\r'。
程序輸出結(jié)果:
41420A43
41420D0A43
請(qǐng)按任意鍵繼續(xù). . .
分別以文本方式和二進(jìn)制方式讀取test1.txt時(shí),輸出的內(nèi)容不同。
可知在以文本方式讀取時(shí),對(duì)'\\r\\n'進(jìn)行了轉(zhuǎn)換,而二進(jìn)制方式讀取時(shí)卻沒(méi)有進(jìn)行這樣的轉(zhuǎn)換(要注意,windows和linux下的換行符是不一樣的,在windows下?lián)Q行符是\\r\\n,即0X0D、0X0A,而在linux下?lián)Q行符是\\n,即0X0A。
3.測(cè)試程序

/*測(cè)試讀操作后能否直接跟寫操作 2011.10.5*/
#include
#include
intmain(void)
{
intch;
intn;
FILE *fp;
if((fp=fopen("test.txt","r+"))==NULL)
{
printf("can not open file\\n");
exit(0);
}
fseek(fp,1L,0);//將fp移動(dòng)到距文件首1字節(jié)的位置
ch=fgetc(fp);
printf("%c\\n",ch);
//rewind(fp);
fseek(fp,1L,0);
fputs("test",fp);
ch=fgetc(fp);
printf("%c\\n",ch);
fclose(fp);
return0;
}

假設(shè)工程已經(jīng)存在文件test.txt,文件中含有字符串"ABCDEFGH"。
則上述程序執(zhí)行結(jié)果為:
B
F
請(qǐng)按任意鍵繼續(xù). . .文件中內(nèi)容為"AtestFGH"。
與預(yù)想結(jié)果相同,因此讀取到字符'B'后,再將位置指針置到距文件首1字節(jié)處,即字符'B'處,寫入"test"后,會(huì)覆蓋掉"BCDE",寫完后位置指針指向字符'F',因此此時(shí)進(jìn)行讀操作,得到的結(jié)果是'F'。
但是如果將fseek(fp,1L,0);這句注釋掉,則執(zhí)行結(jié)果為:
B
G
請(qǐng)按任意鍵繼續(xù). . .
文件中的內(nèi)容為"ABCDEFGH"。
注釋掉fseek一句后,讀取完字符'B'后,位置指針指向字符'C',再進(jìn)行寫操作,位置指針會(huì)向后移動(dòng)4個(gè)字節(jié)的位置,指向字符'G',因此第二次讀取的輸出結(jié)果為'G'。但是文件中的內(nèi)容沒(méi)有被改寫,相當(dāng)于這次寫操作是無(wú)效操作。
4.測(cè)試程序

#include
#include
intmain(void)
{
FILE *fp;
intch;
if((fp=fopen("test","rb"))==NULL)
{
printf("can not open file\\n");
exit(0);
}
ch=fgetc(fp);
while(feof(fp)==0)
{
printf("%02X\\n",ch);
ch=fgetc(fp);
}
fclose(fp);
return0;
}

運(yùn)行此程序之前,用VC6.0建立一個(gè)二進(jìn)制文件test放在工程目錄下,然后輸入數(shù)據(jù)"23 13 0E 1A 35"。保存完畢后再執(zhí)行此程序,執(zhí)行結(jié)果為:
23
13
0E
1A
35
Press any key to continue
但是若將打開(kāi)方式改成"rt",則執(zhí)行結(jié)果為:
23
13
0E
Press any key to continue
之所以出現(xiàn)這種原因,在上面已經(jīng)提到,就是在以文本方式打開(kāi)文件時(shí),若讀取到ASCII碼為26的字符,則會(huì)停止讀取,默認(rèn)文件內(nèi)容已經(jīng)結(jié)束。但是以二進(jìn)制方式打開(kāi)文件則不會(huì)出現(xiàn)這種情況,會(huì)將文件中所有的內(nèi)容原樣輸出(注意這種區(qū)別只在windows下存在,在unix下兩種方式打開(kāi)文件程序的執(zhí)行結(jié)果是相同的即會(huì)原樣輸出文件中所有的內(nèi)容)。