語言中對文件進行操作必須首先打開文件,打開文件主要涉及到fopen函數。fopen函數的原型為
FILE* fopen(const char *path,const char *mode)
其中path為文件路徑,mode為打開方式
1)對于文件路徑,只需注意若未明確給出絕對路徑,則默認該文件在工程的目錄下。若需給出絕對路徑,則注意轉義字符'\\',比如有文件test.txt存放在C盤根目錄下,則文件路徑參數值應為C:\\\\test.txt。
2)對于mode,主要由r,w,a,+,b,t六個字符組合而成。
r:只讀方式,文件必須存在
w:只寫方式,若文件存在,則原有內容會被清除;若文件不存在,則會建立文件
a:追加方式打開只寫文件,只允許進行寫操作,若文件存在,則添加的內容放在文件末尾;若不存在,則建立文件
+:可讀可寫
b:以二進制方式打開文件
t:以文本方式打開文件(默認方式下以文本方式打開文件)
下面是常見的組合:
r: ? ? ?以只讀的方式打開文件,只允許讀,此文件必須存在,否則返回NULL,打開成功后返回文件指針,位置指針指向文件頭部
r+: ? ?以可讀可寫的方式打開文件,允許讀寫,此文件必須存在,否則返回NULL,打開成功后返回文件指針,位置指針指向文件頭部
rb+: ?以可讀可寫、二進制方式打開文件,允許讀寫,此文件必須存在,否則返回NULL,打開成功后返回文件指針,位置指針指向文件頭部
rt+: ?以可讀可寫、文本方式打開文件,允許讀寫,此文件必須存在,否則返回NULL,打開成功后返回文件指針,位置指針指向文件頭部
w: ? ?以只寫的方式打開文件,只允許寫,若文件存在,文件中原有內容會被清除;若文件不存在,則創建文件,打開成功后返回文件指針,位置指針指向文件頭部
w+: ?以讀寫的方式打開文件,允許讀寫,若文件存在,文件中原有內容會被清除;若文件不存在,則創建文件,打開成功后返回文件指針,位置指針指向文件頭部
a: ? ? 以追加、只寫的方式打開文件,只允許寫。若文件存在,則追加的內容添加在文件末尾,若文件不存在,則創建文件。打開成功后返回文件指針,位置指針指向文件頭部(注意很多書上或資料上講述追加方式打開成功后位置指針指向文件末尾是錯誤的)
a+: ? 以追加、可讀寫的方式打開文件,允許讀寫。若進行讀操作,則從頭開始讀;若進行寫操作,則將內容添加在末尾。若文件不存在,則創建文件。打開成功后返回文件指針,位置指針指向文件頭部。
其他方式類似。
下面討論一下以二進制方式和文本方式打開文件有什么區別。
其實這兩種方式打開文件并沒有太大的區別,僅僅只有一點區別就是在處理某些特殊字符的時候。
以文本方式打開文件,若將數據寫入文件,如果遇到換行符'\\n'(ASII
值為10,0A),則會轉換為回車—換行'\\r\\n'(ASII值為13,10,0D0A)存入到文件中,同樣讀取的時候,若遇到回車—換行,即連續的
ASII值13,10,則自動轉換為換行符。
而以二進制方式打開文件時,不會進行這樣的處理。
還有如果以文本方式打開文件時,若讀取到ASCII碼為26(^Z)的字符,則停止對文件的讀取,會默認為文件已結束,而以二進制方式讀取時不會發生這樣
的情況。由于正常情況下我們手動編輯完成的文件是不可能出現ASCII碼為26的字符,所以可以用feof函數去檢測文件是否結束。以上所述的兩點區別只
在windows下存在,在unix下沒有區別。
注意:1)在以追加方式打開文件時,位置指針指向文件的首部。
在這里區分一下位置指針和文件指針:
文件指針:指向存儲文件信息的一個結構體的指針
位置指針:對文件進行讀寫操作時移動的指針
在頭文件中存在一個結構體_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定義了一個文件指針,并成功打開一個文件之后,fp只是指向該結構體,而在對文件進行讀寫操作時,fp的值并不會改變,改變的是結構體中_ptr的值,這個_ptr就是位置指針。
2)以追加方式打開時,若進行寫操作,則rewind函數和fseek函數不會起到作用,因為以追加方式打開時進行寫操作的話,系統會自動將位置指針移動到末尾。
3)當文件打開用于更新時,可以通過文件指針對文件進行讀寫操作,但是如果沒有給出fseek或者rewind的話,讀操作后面不能直接跟寫操作,否則會是無效的寫操作(位置指針會移動,但是需要寫入文件的內容不會被寫入到文件當中),但是寫操作后可以直接跟讀操作。
1.測試程序
假設工程目錄下已存在文件test.txt,文件中含有的字符串為"ABC"
/*測試fopen函數以追加方式打開文件時初始指針的位置 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);//得到此時fp所處位置距文件首的偏移字節數
printf("%d\\n",n);
fputs("test",fp);
n=ftell(fp);
printf("%d\\n",n);
fclose(fp);
return0;
}
輸出結果為:
0
7
Press any key to continue
由輸出結果可知,初始打開文件后,指針是位于文件首部,只是在往文件中添加內容時,才將文件指針移動到文件末尾。
2.測試程序
/*測試以二進制方式和文本方式打開文件的區別 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);//以文本方式向文件中寫入數據
fputc(s[i],fp2);//以二進制方式向文件中寫入數據
}
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))//以文本方式從文件中讀取數據
{
printf("%02X",ch);
ch=fgetc(fp1);
}
printf("\\n");
ch=fgetc(fp2);
while(!feof(fp2))//以二進制方式從文件中讀取數據
{
printf("%02X",ch);
ch=fgetc(fp2);
}
printf("\\n");
fclose(fp1);
fclose(fp2);
return0;
}
在向文件中寫完數據后,用UltraEdit以二進制方式打開test1.txt和test2.txt,看到的結果如下:
根據得到的結果可知,以文本方式寫入時,多寫入了一個字符0D,即'\\r'。
程序輸出結果:
41420A43
41420D0A43
請按任意鍵繼續. . .
分別以文本方式和二進制方式讀取test1.txt時,輸出的內容不同。
可知在以文本方式讀取時,對'\\r\\n'進行了轉換,而二進制方式讀取時卻沒有進行這樣的轉換(要注意,windows和linux下的換行符是不一樣的,在windows下換行符是\\r\\n,即0X0D、0X0A,而在linux下換行符是\\n,即0X0A。
3.測試程序
/*測試讀操作后能否直接跟寫操作 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移動到距文件首1字節的位置
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;
}
假設工程已經存在文件test.txt,文件中含有字符串"ABCDEFGH"。
則上述程序執行結果為:
B
F
請按任意鍵繼續. . .文件中內容為"AtestFGH"。
與預想結果相同,因此讀取到字符'B'后,再將位置指針置到距文件首1字節處,即字符'B'處,寫入"test"后,會覆蓋掉"BCDE",寫完后位置指針指向字符'F',因此此時進行讀操作,得到的結果是'F'。
但是如果將fseek(fp,1L,0);這句注釋掉,則執行結果為:
B
G
請按任意鍵繼續. . .
文件中的內容為"ABCDEFGH"。
注釋掉fseek一句后,讀取完字符'B'后,位置指針指向字符'C',再進行寫操作,位置指針會向后移動4個字節的位置,指向字符'G',因此第二次讀取的輸出結果為'G'。但是文件中的內容沒有被改寫,相當于這次寫操作是無效操作。
4.測試程序
#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;
}
運行此程序之前,用VC6.0建立一個二進制文件test放在工程目錄下,然后輸入數據"23 13 0E 1A 35"。保存完畢后再執行此程序,執行結果為:
23
13
0E
1A
35
Press any key to continue
但是若將打開方式改成"rt",則執行結果為:
23
13
0E
Press any key to continue
之所以出現這種原因,在上面已經提到,就是在以文本方式打開文件時,若讀取到ASCII碼為26的字符,則會停止讀取,默認文件內容已經結束。但是以二進制方式打開文件則不會出現這種情況,會將文件中所有的內容原樣輸出(注意這種區別只在windows下存在,在unix下兩種方式打開文件程序的執行結果是相同的即會原樣輸出文件中所有的內容)。