欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C語言文件操作入門指南

 更新時間:2024年08月07日 10:49:12   作者:南風與魚  
我們在想既然是通訊錄就應(yīng)該把信息記錄下來,只有我們自己選擇刪除數(shù)據(jù)的時候,數(shù)據(jù)才不復(fù)存在,這就涉及到了數(shù)據(jù)持久化的問題,我們一般數(shù)據(jù)持久化的方法有,把數(shù)據(jù)存放在磁盤文件、存放到數(shù)據(jù)庫等方式,使用文件我們可以將數(shù)據(jù)直接存放在電腦的硬盤上,做到了數(shù)據(jù)的持久化

一、為什么使用文件

在學(xué)習(xí)完結(jié)構(gòu)體后,為了檢驗學(xué)習(xí)成果,我們寫了一個通訊錄的小程序,當通訊錄運行起來的時候,可以給通訊錄中增加、刪除數(shù)據(jù),此時數(shù)據(jù)是存放在內(nèi)存中的,當程序退出的時候,通訊錄中的數(shù)據(jù)就不存在了,等下次運行通訊錄程序的時候,數(shù)據(jù)又得重新錄入,如果使用這樣的通訊錄就很難受。

我們在想既然是通訊錄就應(yīng)該把信息記錄下來,只有我們自己選擇刪除數(shù)據(jù)的時候,數(shù)據(jù)才不復(fù)存在。

這就涉及到了數(shù)據(jù)持久化的問題,我們一般數(shù)據(jù)持久化的方法有,把數(shù)據(jù)存放在磁盤文件、存放到數(shù)據(jù)庫等方式。使用文件我們可以將數(shù)據(jù)直接存放在電腦的硬盤上,做到了數(shù)據(jù)的持久化。

二、什么是文件

  • 磁盤上的文件是文件。
  • 在程序設(shè)計中,我們一般談的文件有兩種:程序文件、數(shù)據(jù)文件(從文件功能的角度來分類的)。

2.1 程序文件

包括源程序文件(后綴為.c),目標文件(windows環(huán)境后綴為.obj),可執(zhí)行程序(windows環(huán)境后綴為.exe)。

2.2 數(shù)據(jù)文件

文件的內(nèi)容不一定是程序,而是程序運行時讀寫的數(shù)據(jù),比如程序運行需要從中讀取數(shù)據(jù)的文件,或者輸出內(nèi)容的文件。

??在前面我們所處理數(shù)據(jù)的輸入輸出都是以終端為對象的,即從終端的鍵盤輸入數(shù)據(jù),運行結(jié)果顯示到顯示器上。
??其實有時候我們會把信息輸出到磁盤上,當需要的時候再從磁盤上把數(shù)據(jù)讀取到內(nèi)存中使用,這里處理的就是磁盤上文件。

2.3 文件名

  • 一個文件要有一個唯一的文件標識,以便用戶識別和引用
  • 文件名包含3部分:文件路徑+文件名主干+文件后綴
  • 例如: c:\code\test.txt

三、文件的打開和關(guān)閉

3.1 文件指針

緩沖文件系統(tǒng)中,關(guān)鍵的概念是“文件類型指針”,簡稱“文件指針”。每個被使用的文件都在內(nèi)存中開辟了一個相應(yīng)的文件信息區(qū),用來存放文件的相關(guān)信息(如文件的名字,文件狀態(tài)及文件當前的位置等)。這些信息是保存在一個結(jié)構(gòu)體變量中的。該結(jié)構(gòu)體類型是有系統(tǒng)聲明的,取名FILE。

??例如,VS2013編譯環(huán)境提供的 stdio.h 頭文件中有以下的文件類型申明:

struct _iobuf
{
	char* _ptr;
	int _cnt;
	char* _base;
	int _flag;
	int _file;
	int _charbuf;
	int _bufsiz;
	char* _tmpfname;
};
typedef struct _iobuf FILE;
  •  不同的C編譯器的FILE類型包含的內(nèi)容不完全相同,但是大同小異。
  • 每當打開一個文件的時候,系統(tǒng)會根據(jù)文件的情況自動創(chuàng)建一個FILE結(jié)構(gòu)的變量,并填充其中的信息,我們在使用時不必關(guān)心其細節(jié)。
  • 一般都是通過一個FILE的指針來維護這個FILE結(jié)構(gòu)的變量,這樣使用起來更加方便。

?下面我們可以創(chuàng)建一個FILE*的指針變量:

FILE* pf;//文件指針變量
定義pf是一個指向FILE類型數(shù)據(jù)的指針變量。可以使pf指向某個文件的文件信息區(qū)(是一個結(jié)構(gòu)體變量)。通過該文件信息區(qū)中的信息就能夠訪問該文件。也就是說,通過文件指針變量能夠找到與它關(guān)聯(lián)的文件。

??比如:

 

3.2 文件的打開和關(guān)閉

文件在讀寫之前應(yīng)該先打開文件,在使用結(jié)束之后應(yīng)該關(guān)閉文件。
在編寫程序的時候,在打開文件的同時,都會返回一個FILE*的指針變量指向該文件,也相當于建立了指針和文件的關(guān)系。

ANSIC 規(guī)定使用fopen函數(shù)來打開文件,fclose來關(guān)閉文件:

//打開文件
FILE * fopen ( const char * filename, const char * mode );
//關(guān)閉文件
int fclose ( FILE * stream );

??????打開方式如下:


 

??示例代碼:

#include <stdio.h>
 
int main()
{
	//打開文件
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//關(guān)閉文件
	fclose(pf);
	pf == NULL;
 
	return 0;
}

注意:我們平常所寫的程序保存數(shù)據(jù)是保存在內(nèi)存當中的,而我們想把內(nèi)存當中的數(shù)據(jù)放在文件當中去,文件又是在硬盤上的,所以把內(nèi)存當中的數(shù)據(jù)往硬盤上放的這個操作叫做寫文件或輸出操作,把文件當中的數(shù)據(jù)往內(nèi)存里邊放的操作叫讀文件或輸入操作。

四、文件的順序讀寫

 

??深入理解 “流”:

  • 在C語言中,流可以分為文件流和輸入輸出流。
  • 流是一個高度抽象的概念,我們可以把它理解為信息流或者水流,在寫文件的過程中,會有很多的數(shù)據(jù),這些數(shù)據(jù)可能會傳輸?shù)讲煌牡胤饺?,比如說顯示到屏幕上,存到硬盤上,傳到網(wǎng)絡(luò)上等等,這些統(tǒng)稱為外部設(shè)備,不同的外部設(shè)備操作方式也不同。
  • 要把數(shù)據(jù)傳到各種外部設(shè)備上去,就對程序員有較高的要求了,這時候就有人想把這個過程簡化一下,在外部設(shè)備和數(shù)據(jù)之間抽象一個東西,這個東西我們就叫做流,它里邊流淌的都是數(shù)據(jù),程序員現(xiàn)在只關(guān)心把數(shù)據(jù)怎么放在流里邊,至于流怎么把數(shù)據(jù)放在外部設(shè)備上去,那就不是我們要操心的事兒了,這樣一來,整個過程就簡單了許多。
  • 回憶一下我們曾經(jīng)用scanf從鍵盤上讀取數(shù)據(jù),或用printf向屏幕上打印數(shù)據(jù),直接就操作了,好像沒有打開鍵盤或打開屏幕的操作,這是因為C語言程序只要運行起來,就會默認打開三個流,分別為:標準輸入流 --- stdin、標準輸出流 --- stdout、標準錯誤流 --- stderr。因為scanf從鍵盤上讀取數(shù)據(jù)其實就是從標準輸入流里邊讀取數(shù)據(jù),而printf向屏幕上打印數(shù)據(jù)就是向標準輸出流里邊打印數(shù)據(jù),所以我們讀取數(shù)據(jù)或輸入數(shù)據(jù)的時候并沒有發(fā)現(xiàn)打開鍵盤或打開屏幕的操作。
  • 文件流是用于文件讀寫操作的數(shù)據(jù)流,它可以從文件中讀取數(shù)據(jù),也可以向文件中寫入數(shù)據(jù),另外,文件流需要指定文件路徑和文件名,而標準輸出流不需要指定文件路徑,直接輸出到屏幕上。

 ??使用輸出流向屏幕輸出26個英文字母:

int main()
{
	char ch = 0;
	for (ch = 'a'; ch < 'z'; ch++)
	{
		if (ch % 5 == 0)
			fputc('\n', stdout);
		fputc(ch, stdout);
	}
	return 0;
}

??文件的順序讀寫函數(shù)介紹: 

??fputc函數(shù):

1.函數(shù)原型:

int fputc ( int character, FILE * stream );

2.功能:

向指定的文件流中寫入一個字符。

3.示例: 

int main()
{
	//打開文件
	FILE* pf = fopen("test.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//寫文件
	fputc('a', pf);
	fputc('b', pf);
	fputc('c', pf);
	fputc('d', pf);
 
	//關(guān)閉文件
	fclose(pf);
	pf = NULL;
 
	return 0;
}

在上述程序中,剛開始我們打開一個文件,它里邊什么都沒有 ,但是我有一個文件指針是指向這個文件的起始位置的(這兒所說的文件指針是指標記字符位置的指針即光標,而不是pf);如果打開成功,接下來就要寫文件,最開始文件指針是指向第一個位置的,所以fputc把a寫了進去,這時候文件指針的狀態(tài)就會更新,指向a的后邊,然后fputc再把b寫進去,每一次進行寫操作后,文件指針的位置就要發(fā)生變化,直到把所有的字符都寫進去。然后fclose關(guān)閉文件,將文件保存起來。

??fgetc函數(shù): 

1.函數(shù)原型:

int fgetc ( FILE * stream );
stream:要從中讀取字符的文件流。 

2.功能:

從指定的文件流中讀取一個字符,并返回其ASCII值。

3.示例: 


 

程序運行起來后,先打開文件,如果成功,就開始讀文件,讀文件的時候光標默認在最前面,當fgetc讀一個字符的時候,光標指向的那個位置為a,所以就返回字符a的ASCII值,然后打印在屏幕上,以同樣的步驟操作三次,就會將a、b、c分別打印在屏幕上,緊接著關(guān)閉文件。

??fputs函數(shù):

1.函數(shù)原型:

int fputs ( const char * str, FILE * stream );

str:要寫入文件的字符串。stream:要寫入的文件流。

2.功能:

向指定的文件流中寫入一行文本。

3.示例: 

int main()
{
	//打開文件
	FILE* pf = fopen("test.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//寫文件
	//寫到文件中去
	fputs("hello\n", pf);
	fputs("world!\n", pf);
	//寫到屏幕上去
	fputs("hello\n", stdout);
	fputs("world!\n", stdout);
 
	//關(guān)閉文件
	fclose(pf);
	pf = NULL;
 
	return 0;
}

 ??fgets函數(shù):

1.函數(shù)原型:

char * fgets ( char * str, int num, FILE * stream );

str:指向用于存儲讀取字符串的字符數(shù)組的指針。num:要讀取的最大字符數(shù)(num - 1個)。stream:要從中讀取行的文件流。

2.功能:

從指定的文件流中讀取一行文本,并將其存儲到指定的字符串中。

3.示例: 

int main(){//打開文件FILE* pf = fopen("test.txt", "r");if (pf == NULL){perror("fopen");return 1;}//讀文件char arr[10] = { 0 };fgets(arr, 3, pf);//關(guān)閉文件fclose(pf);pf = NULL;return 0;}

因為它讀取的最大字符數(shù)是num - 1個,所以只存儲了前兩個字符。 

 ??fprintf函數(shù):

1.函數(shù)原型:

int fprintf ( FILE * stream, const char * format, ... );

stream:要寫入數(shù)據(jù)的文件流。format:格式字符串,指定了要寫入的數(shù)據(jù)的格式。...:要寫入數(shù)據(jù)的變量列表。

2.功能:

向指定的文件流中按照指定格式寫入數(shù)據(jù)。

3.示例: 

struct S
{
	float f;
	char c;
	int n;
};
 
int main()
{
	struct S s = { 3.14f, 'w', 100 };
	//打開文件
	FILE* pf = fopen("test.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//寫文件
	fprintf(pf, "%f %c %d", s.f, s.c, s.n);
 
	//關(guān)閉文件
	fclose(pf);
	pf = NULL;
 
	return 0;
}

??fscanf函數(shù):

 1.函數(shù)原型:

int fscanf ( FILE * stream, const char * format, ... );stream:要從中讀取數(shù)據(jù)的文件流。format:格式字符串,指定了要讀取的數(shù)據(jù)的格式。...:要讀取的數(shù)據(jù)的變量列表。

2.功能:

從指定的文件流中按照指定的格式讀取數(shù)據(jù)。

3.示例: 

struct S
{
	float f;
	char c;
	int n;
};
 
int main()
{
	struct S s = { 0 };
	//打開文件
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//寫文件
	fscanf(pf, "%f %c %d", &(s.f), &(s.c), &(s.n));
	printf("%f %c %d\n", s.f, s.c, s.n);
 
	//關(guān)閉文件
	fclose(pf);
	pf = NULL;
 
	return 0;
}

??fwrite函數(shù):

 1.函數(shù)原型:

size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );

  • ptr:指向要寫入的數(shù)據(jù)的緩沖區(qū)的指針。
  • size:每個數(shù)據(jù)的字節(jié)數(shù)。
  • count:要寫入的數(shù)據(jù)塊的數(shù)量。
  • stream:要寫入數(shù)據(jù)的文件流。

2.功能:

向指定的文件流中寫入指定數(shù)量的數(shù)據(jù)塊。

3.示例: 

//二進制的方式寫進文件
int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	//打開文件
	FILE* pf = fopen("text.txt", "wb");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//二進制的寫文件
	fwrite(arr, sizeof(arr[0]), sizeof(arr) / sizeof(arr[0]), pf);
 
	//關(guān)閉文件
	fclose(pf);
	pf = NULL;
 
	return 0;
}

可以看到寫進去的值都變成了二進制,我們看不懂,但是我們也可以以二進制的方式讀取文件。 

fread函數(shù):

  1.函數(shù)原型:

size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );

  • ptr:指向存儲讀取數(shù)據(jù)的緩沖區(qū)的指針。
  • size:每個數(shù)據(jù)的字節(jié)數(shù)。
  • count:要讀取的數(shù)據(jù)塊的數(shù)量。
  • stream:要讀取數(shù)據(jù)的文件流。

2.功能:

從指定的文件流中讀取指定數(shù)量的數(shù)據(jù)塊。 

3.示例: 

//二進制的方式讀取文件
int main()
{
	int arr[10] = { 0 };
	//打開文件
	FILE* pf = fopen("text.txt", "rb");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//二進制的讀文件
	fread(arr, sizeof(arr[0]), sizeof(arr) / sizeof(arr[0]), pf);
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);
	}
 
	//關(guān)閉文件
	fclose(pf);
	pf = NULL;
 
	return 0;
}

 ??對比一組函數(shù):

scanf、fscanf、sscanf

printf、fprintf、sprintf

scanf是格式化的輸入函數(shù),針對的是標準輸入流 (鍵盤);printf是格式化的輸出函數(shù),針對的是標準輸出流(屏幕);綜上所述,scanf和printf是針對標準輸入/輸出流的格式化輸入/輸出函數(shù)。

fscanf是針對所有輸入流(文件流、標準輸入流)的格式化輸入函數(shù);sprintf是針對所有輸出流(文件流、標準輸出流)的格式化輸出函數(shù)。

sprintf是把格式化的數(shù)據(jù)轉(zhuǎn)化換成字符串;sscanf是將字符串轉(zhuǎn)換成格式化數(shù)據(jù)。

struct S
{
	float f;
	char c;
	int n;
};
 
int main()
{
	struct S s = { 3.14f, 'c', 100 };
	char arr[100] = { 0 };
	sprintf(arr, "%f %c %d", s.f, s.c, s.n);
	printf("%s\n", arr);
 
	struct S tmp = { 0 };
	sscanf(arr, "%f %c %d", &(tmp.f), &(tmp.c), &(tmp.n));
	printf("%f\n", tmp.f);
	printf("%c\n", tmp.c);
	printf("%d\n", tmp.n);
	return 0;
}

 

五、文件的隨機讀寫

5.1 fseek函數(shù):

  1.函數(shù)原型:

int fseek ( FILE * stream, long int offset, int origin );

stream:指向FILE對象的指針,它標識了要定位的文件。

offset:偏移量,即要移動的字節(jié)數(shù)??梢詾檎龜?shù)、負數(shù)或0,具體取決于origin參數(shù)。

origin:定位的起始位置,可以是下列常量之一:

SEEK_SET:從文件開頭開始偏移。SEEK_CUR:從當前位置開始偏移。SEEK_END:從文件末尾開始偏移。

返回值:如果定位成功,fseek函數(shù)返回0;如果失敗,返回非零值。

2.功能:

 fseek函數(shù)用于設(shè)置文件位置指針,以便在文件中進行定位。它可以將文件位置指針設(shè)置到文件的任意位置,從而可以進行讀取或?qū)懭氩僮鳌?/p>

3.示例:

int main()
{
	//打開文件
	FILE* pf = fopen("text.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
 
	int ch = fgetc(pf);
	printf("%c\n", ch);//a
 
	ch = fgetc(pf);
	printf("%c\n", ch);//b
 
	//ch = fgetc(pf);
	//printf("%c\n", ch);//c
 
	//fseek(pf, -2, SEEK_CUR);//從當前位置開始偏移
	//fseek(pf, 0, SEEK_SET);//從文件的開頭開始偏移
	fseek(pf, -6, SEEK_END);//從文件的末尾開始偏移
 
	ch = fgetc(pf);
	printf("%c\n", ch);//a
 
	//關(guān)閉文件
	fclose(pf);
	pf = NULL;
	return 0;
}

 

我的文件中放著一串字符串“abcdef”, 現(xiàn)在我想從中讀取字符出來,用fgetc函數(shù)就可以,但我想讓它第三個字符讀的是a,這個時候就可以用fseek函數(shù)。

5.2 ftell函數(shù):

1.函數(shù)原型: 

long int ftell ( FILE * stream );stream:指向FILE對象的指針,用于標識要獲取位置的文件。返回值:返回當前位置相對于文件開頭的偏移量,如果出現(xiàn)錯誤則返回-1。

2. 功能: 

用于獲取文件位置指針的當前位置,即返回當前位置相對于文件開頭的偏移量。

3.示例:

int main()
{
	//打開文件
	FILE* pf = fopen("text.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
 
	int ch = fgetc(pf);
	printf("%c\n", ch);//a
 
	ch = fgetc(pf);
	printf("%c\n", ch);//b
 
	ch = fgetc(pf);
	printf("%c\n", ch);//c
	
	int pos = ftell(pf);
	printf("pos= %d\n", pos);
 
	//關(guān)閉文件
	fclose(pf);
	pf = NULL;
	return 0;
}

5.3 rewind函數(shù):

1. 函數(shù)原型:

void rewind ( FILE * stream ); stream:指向FILE對象的指針,用于標識要重新定位的文件。

2.功能:

用于將文件位置指針重新定位到文件的開頭,即相當于調(diào)用fseek(stream, 0, SEEK_SET)。

3.示例:

int main()
{
	//打開文件
	FILE* pf = fopen("text.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
 
	int ch = fgetc(pf);
	printf("%c\n", ch);//a
 
	ch = fgetc(pf);
	printf("%c\n", ch);//b
 
	//ch = fgetc(pf);
	//printf("%c\n", ch);//c
 
	rewind(pf);
 
	ch = fgetc(pf);
	printf("%c\n", ch);//a
 
	//關(guān)閉文件
	fclose(pf);
	pf = NULL;
	return 0;
}

六、文本文件和二進制文件

  • 根據(jù)數(shù)據(jù)的組織形式,數(shù)據(jù)文件被稱為文本文件或者二進制文件。
  • 數(shù)據(jù)在內(nèi)存中以二進制的形式存儲,如果不加轉(zhuǎn)換的輸出到外存,就是二進制文件。
  • 如果要求在外存上以ASCII碼的形式存儲,則需要在存儲前轉(zhuǎn)換。以ASCII字符的形式存儲的文件就是文本文件。

那一個數(shù)據(jù)在內(nèi)存中是怎么存儲的呢?

字符一律以ASCII形式存儲,數(shù)值型數(shù)據(jù)既可以用ASCII形式存儲,也可以使用二進制形式存儲。如有整數(shù)10000,如果以ASCII碼的形式輸出到磁盤,則磁盤中占用5個字節(jié)(每個字符一個字節(jié)),而以二進制形式輸出,則在磁盤上只占4個字節(jié)(VS2013測試)。


 

??測試代碼:

我們將10000以 二進制的形式寫到文件中,就是上述效果,我們自己是看不懂的,但VS卻能看懂,具體操作步驟如下圖:

int main()
{
	int a = 10000;
	FILE* pf = fopen("test.txt", "wb");
	//二進制的形式寫到文件中
	fwrite(&a, 4, 1, pf);
 
	fclose(pf);
	pf = NULL;
 
	return 0;
}

 

將10000轉(zhuǎn)換成二進制為 0010 0111 0001 0000,這是16個二進制位,不夠32位,我們給它補齊0000 0000 0000 0000 0010 0111 0001 0000,每4個二進制位轉(zhuǎn)換成1個16進制位,就為0x00 0x00 0x27 0x10,那在內(nèi)存中以小端方式存放就為10 27 00 00。

七、文件讀取結(jié)束的判定 

7.1 文本文件的讀取結(jié)束判定

文本文件讀取是否結(jié)束,判斷返回值是否為 EOF ( fgetc ),或者 NULL ( fgets )。fgetc 判斷是否為 EOF 。fgets 判斷返回值是否為 NULL。

ferror:在文件讀取結(jié)束后,用來判斷文件是否因為讀取過程中遇到錯誤而結(jié)束。feof:在文件讀取結(jié)束后,用來判斷文件是否因為讀取過程中遇到文件結(jié)束標志而結(jié)束。牢記:在文件讀取過程中,不能用feof函數(shù)的返回值直接用來判斷文件是否結(jié)束。而是應(yīng)用于當文件讀取結(jié)束的時候,判斷是讀取失敗結(jié)束,還是遇到文件尾結(jié)束 。

 示例:

#include <stdio.h>
#include <stdlib.h>
 
int main()
{
	int c; // 注意:是int而非char,因為要求處理EOF,而EOF實際是-1,是個整型值
	FILE* fp = fopen("test.txt", "r");
	if (!fp) 
	{
		perror("fopen");
		return 1;
	}
	//fgetc 當讀取失敗的時候或者遇到文件結(jié)束的時候,都會返回EOF
	while ((c = fgetc(fp)) != EOF) // 標準C I/O讀取文件循環(huán)
	{
		putchar(c);
	}
	//判斷是什么原因結(jié)束的
	if (ferror(fp))
		puts("I/O error when reading");
	else if (feof(fp))
		puts("End of file reached successfully");
	fclose(fp);
}

7.2 二進制文件的讀取結(jié)束判定

fread函數(shù)判斷返回值是否小于實際要讀的個數(shù)。

size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );fread要求讀取count個大小為size字節(jié)的數(shù)據(jù)。如果真的讀取到count個數(shù)據(jù),函數(shù)返回count。如果沒有讀取到count個數(shù)據(jù),返回的是真實讀取到的完整的數(shù)據(jù)個數(shù)。

示例:

#include <stdio.h>
 
enum { SIZE = 5 };
int main()
{
	double a[SIZE] = { 1.,2.,3.,4.,5. };
	FILE* fp = fopen("test.bin", "wb"); // 必須用二進制模式
	fwrite(a, sizeof * a, SIZE, fp); // 寫 double 的數(shù)組
	fclose(fp);
	double b[SIZE];
	fp = fopen("test.bin", "rb");
	size_t ret_code = fread(b, sizeof * b, SIZE, fp); // 讀 double 的數(shù)組
	if (ret_code == SIZE) 
	{
		puts("Array read successfully, contents: ");
		for (int n = 0; n < SIZE; ++n) 
			printf("%f ", b[n]);
		putchar('\n');
	}
	else 
	{ // error handling
		if (feof(fp))
			printf("Error reading test.bin: unexpected end of file\n");
		else if (ferror(fp)) 
		{
			perror("Error reading test.bin");
		}
	}
	fclose(fp);
	return 0;
}

 八、文件緩沖區(qū)

ANSIC 標準采用“緩沖文件系統(tǒng)”處理數(shù)據(jù)文件,所謂緩沖文件系統(tǒng)是指系統(tǒng)自動地在內(nèi)存中為程序中每一個正在使用的文件開辟一塊“文件緩沖區(qū)”。從內(nèi)存向磁盤輸出數(shù)據(jù)會先送到內(nèi)存中的緩沖區(qū),裝滿緩沖區(qū)后才一起送到磁盤上。如果從磁盤向計算機讀入數(shù)據(jù),則從磁盤文件中讀取數(shù)據(jù)輸入到內(nèi)存緩沖區(qū)(充滿緩沖區(qū)),然后再從緩沖區(qū)逐個地將數(shù)據(jù)送到程序數(shù)據(jù)區(qū)(程序變量等),緩沖區(qū)的大小根據(jù)C編譯系統(tǒng)決定。

#include <stdio.h>
#include <windows.h>
 
//VS2019 WIN10環(huán)境測試
int main()
{
	FILE* pf = fopen("test.txt", "w");
	fputs("abcdef", pf);//先將代碼放在輸出緩沖區(qū)
	printf("睡眠10秒-已經(jīng)寫數(shù)據(jù)了,打開test.txt文件,發(fā)現(xiàn)文件沒有內(nèi)容\n");
	Sleep(10000);
	printf("刷新緩沖區(qū)\n");
	fflush(pf);//刷新緩沖區(qū)時,才將輸出緩沖區(qū)的數(shù)據(jù)寫到文件(磁盤)
	//注:fflush 在高版本的VS上不能使用了
	printf("再睡眠10秒-此時,再次打開test.txt文件,文件有內(nèi)容了\n");
	Sleep(10000);
	fclose(pf);
	//注:fclose在關(guān)閉文件的時候,也會刷新緩沖區(qū)
	pf = NULL;
	return 0;
}

通過以上測試,可以得出一個結(jié)論:

因為有緩沖區(qū)的存在,C語言在操作文件的時候,需要做刷新緩沖區(qū)或者在文件操作結(jié)束的時候關(guān)閉文件。如果不做,可能導(dǎo)致讀寫文件的問題。

相關(guān)文章

  • C++設(shè)計模式之解釋器模式

    C++設(shè)計模式之解釋器模式

    這篇文章主要介紹了C++設(shè)計模式之解釋器模式,本文講解了什么是解釋器模式、文法規(guī)則和抽象語法樹、解釋器模式的使用場合等內(nèi)容,需要的朋友可以參考下
    2014-10-10
  • C++實現(xiàn)病人就醫(yī)管理系統(tǒng)

    C++實現(xiàn)病人就醫(yī)管理系統(tǒng)

    這篇文章主要為大家詳細介紹了C++語言實現(xiàn)病人就醫(yī)管理系統(tǒng),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-01-01
  • C語言 小游戲打磚塊實現(xiàn)流程詳解

    C語言 小游戲打磚塊實現(xiàn)流程詳解

    打磚塊游戲是一種動作電子游戲的名稱。玩家操作一根螢?zāi)簧纤降摹鞍糇印?,讓一顆不斷彈來彈去的“球”在撞擊作為過關(guān)目標消去的“磚塊”的途中不會落到螢?zāi)坏紫?。球碰到磚塊、棒子與底下以外的三邊會反彈,落到底下會失去一顆球,把磚塊全部消去就可以破關(guān)
    2021-11-11
  • C語言實現(xiàn)的統(tǒng)計素數(shù)并求和代碼分享

    C語言實現(xiàn)的統(tǒng)計素數(shù)并求和代碼分享

    這篇文章主要介紹了C語言實現(xiàn)的統(tǒng)計素數(shù)并求和代碼分享,來自PAT平臺(浙江大學(xué)計算機程序設(shè)計能力考試系統(tǒng))的一個題目,需要的朋友可以參考下
    2014-08-08
  • 插入排序算法之希爾排序+直接插入排序

    插入排序算法之希爾排序+直接插入排序

    這篇文章主要介紹了插入排序算法之希爾排序+直接插入排序的相關(guān)知識,本文通過實例圖文相結(jié)合給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-11-11
  • Vscode搭建遠程c開發(fā)環(huán)境的圖文教程

    Vscode搭建遠程c開發(fā)環(huán)境的圖文教程

    很久沒有寫C語言了,今天抽空學(xué)習(xí)下C語言知識,接下來通過本文給大家介紹Vscode搭建遠程c開發(fā)環(huán)境的詳細步驟,本文通過圖文實例代碼相結(jié)合給大家介紹的非常詳細,需要的朋友參考下吧
    2021-11-11
  • C++實現(xiàn)簡單的HTTP服務(wù)器

    C++實現(xiàn)簡單的HTTP服務(wù)器

    這篇文章主要為大家詳細介紹了C++實現(xiàn)簡單的HTTP服務(wù)器的相關(guān)資料,感興趣的朋友可以參考下
    2016-05-05
  • C語言簡易版flappy bird小游戲

    C語言簡易版flappy bird小游戲

    這篇文章主要為大家詳細介紹了C語言簡易版flappy bird小游戲,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-12-12
  • 基于C++類型重定義的使用詳解

    基于C++類型重定義的使用詳解

    本篇文章是對C++中類型重定義的使用進行了詳細的分析介紹,需要的朋友參考下
    2013-05-05
  • C++?STL容器詳解之紅黑樹部分模擬實現(xiàn)

    C++?STL容器詳解之紅黑樹部分模擬實現(xiàn)

    本文主要對紅黑樹進行了詳細介紹,并對其核心功能進行了模擬實現(xiàn)。文中的代碼對我們的學(xué)習(xí)或工作有一定的價值,感興趣的小伙伴可以了解一下
    2021-12-12

最新評論