1. 程式人生 > >C/C++中讀取檔案判斷是否讀取結束

C/C++中讀取檔案判斷是否讀取結束

最近用C++讀取檔案時遇到了一個問題,讀取如下圖所示的檔案時,使用C中的feof()判斷是否讀取結束,總會在檔案末尾處總會多讀一遍。

可以看到我讀取的檔案格式是比較簡單的,沒兩行為一對,第一行有兩個int型別的數字,第二行是一個字串,包含影象的名稱。

先上我讀取檔案的程式碼:

void read(string name)
{
	FILE *file = fopen(name.c_str(), "r");
	while (!feof(file))
	{
		int i, j;
		fscanf(file, "%d%d\n", &i, &j);

		char filename[100];
		fgets(filename, 100, file);
		filename[strlen(filename) - 1] = '\0';
	}
}

可以看到,讀取的程式碼非常簡單,但是這樣會出現一個問題,最後一行會重複輸出一遍。

造成這個問題的原因在於feof在真正檔案讀取結束後還會繼續在判斷一遍才會結束。

為了解決這個問題,有人是使用瞭如下方法

char c;
c = fgetc(fp);
while(!feof(fp))
{
	printf("%X/n", c); 
	c = fgetc(fp);
} 	printf("%X/n", c); 
	c = fgetc(fp);
} 

這種方法確實可以避免重複讀取最後一行的問題,但是這種方法更加適合於每次讀取單個字元的情況,對於我遇到的這種,需要讀取int和字串的情況就不是很適用,最終我在網上找到了一種萬無一失的方法解決feof的問題,那就是不用它。。。

我們適用fseek和ftell來配合判斷是否讀取到檔案末尾。

void read(string name)
{
	FILE *file = fopen(name.c_str(), "r");

	fseek(file, 0L, SEEK_END);
	long end = ftell(file);
	fseek(file, 0L, SEEK_SET);
	long start = ftell(file);

	while (end != start)
	{
		int i, j;
		fscanf(file, "%d%d\n", &i, &j);

		char filename[100];
		fgets(filename, 100, file);
		if (filename[strlen(filename) - 1] == '\n')
			filename[strlen(filename) - 1] = '\0';

		cout << filename << endl;
		start = ftell(file);
	}
}

大體思路就是首先通過fseek得到檔案末尾的位置,然後在讀取檔案以後不斷計算當前讀取的檔案位置,如果讀取後發現當前位置與檔案末尾位置相同,則停止繼續讀取檔案。

這種方法的好處是萬金油,記住這一種,以後遇到所有需要讀取全部檔案的情況都可以適用。簡單易懂。

當然利用C++的方法也可以實現這一需求,但是有些情況下C++的讀寫速度明顯低於C語言,而且C++相容C語言。