轉載自:http://blog.csdn.net/zhy10/article/details/1562649
轉載自:http://blog.csdn.net/sambian/article/details/644360
EOF,即end of file,文件結尾,作為文件結束的標志,在程序中常作為判斷的一個標志。但在我們平常的程序中卻常發生意想不到的結果。
下面這段程序,猜猜它輸出的是什么?
char c;
ifstream fin("d://dat");//設d:/dat文件已存在,內容為ab。
while(!fin.eof())
{
fin >> c;
cout << c;
}
輸出結果是abb,沒想到嗎?你可能會問,再輸出第一個b的時候,文件指針已經指向了EOF,為何不結束?
問題的關鍵是文件EOF機制是怎樣運作的。
我們來談三個問題:
1、文件指針
當打開一個文件時,文件指針位置為0,並不是指向第一個字符,即第一個字符的位置為1。這一點我們可以通過peek()函數驗證。peek()返回的是當前文件指針下一個位置的字符。所以有:
ofstream fo("d://dat");
fo << 'h';
fo.close();
ifstream fi("d://dat");
char temp = fi.peek();
cout << temp;
會顯示h。
還有,用fo.seekp(0,ios::beg),得文件指針為0;fo.seekp(0,ios::end),得文件指針指向最后一個字符。
2、關於EOF
很多朋友認為文件尾有EOF,這是錯誤的。EOF是流的狀態標志。在 C++中,是在讀取文件失敗時才產生EOF。所以第一個程序中,在輸出第一個b時,產生了EOF,再輸出第二個b時讀取到EOF,循環結束。
3、解決EOF困惑的辦法
我感覺在判斷文件結束上,最好的方法就是判斷文件指針相對於開頭的位置,是否等於文件長度。即:
long filelen;
ifstream fin("d://dat");//設d:/dat文件已存在,內容為ab。
fin.seekg(0,ios::end);
filelen = fin.tellg();//獲取文件長度
fin.seekg(0,ios::beg);
while (1)
{
if (filelen == fin.tellg())//到達文件尾,即指向EOF
{
flag = true;
break;
}
讀取數據...
}
當然還有別的方法,就是用peek()的預讀性。
peek()返回當前文件指針下一個位置的字符,而指針位置不變。所以我們可以這樣:
while (fi.peel()!=EOF)
{
...
}
當while循環體中,文件指針指向最后一個字符,若沒有fi.peel()!=EOF,則需要再下一個循環中才能觸發EOF。而加了fi.peel()!=EOF后,用預讀的方法檢測出了EOF。
#include <stdio.h>
int main()
{
FILE *in,*out;
char ch,infile[10],outfile[10];
printf("Enter the infile name:");
scanf("%s",infile);
in=fopen(infile,"r");
if(in==NULL)
{
printf("Can't open the file that you want read!");
return 1;
}
printf("Enter the outfile name:");
scanf("%s",outfile);
out=fopen(outfile,"w");
if(out==NULL)
{
printf("Can't open the file that you want to write!");
return 1;
}
while(!feof(in))
{
ch=fgetc(in);
putchar(ch);
fputc(ch,out);
}
fclose(in);
fclose(out);
return 0;
}
上面這個小程序,每次運行后,目標文件會比源文件多一個字節,比如,源文件Test1.txt的內容是:
hehe
運行后,目標文件Test2.txt的內容卻是:
hehe
用記事本打開看的,多了一個字節,變成了5字節
上面這段程序在譚浩強的C程序設計(第二版)中也有這個問題,這實際上是對feof這個函數的處理方式不理解所造成的,實際上:
當feof(FILE *)讀到EOF標志並不認為文件結束了,依舊返回0,直到讀到EOF的下一個字符才返回1,這時才認為是文件結束。
因此若以while(!feof(fp))為循環條件的時候,要將一個文件(fp)完全復制到另一個文件(fp1),需要加上判斷if(ch!=-1),如下:
while(!feof(in))
{
ch=fgetc(in);
if(ch!=-1)
fputc(ch,out);
}
或者:
while(true)
{
ch=fgetc(in);
if(feof(in))
break;
putchar(ch);
fputc(ch,out);
}