亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

C語(yǔ)言文件操作入門指南

 更新時(shí)間:2024年08月07日 10:49:12   作者:南風(fēng)與魚  
我們?cè)谙爰热皇峭ㄓ嶄浘蛻?yīng)該把信息記錄下來(lái),只有我們自己選擇刪除數(shù)據(jù)的時(shí)候,數(shù)據(jù)才不復(fù)存在,這就涉及到了數(shù)據(jù)持久化的問題,我們一般數(shù)據(jù)持久化的方法有,把數(shù)據(jù)存放在磁盤文件、存放到數(shù)據(jù)庫(kù)等方式,使用文件我們可以將數(shù)據(jù)直接存放在電腦的硬盤上,做到了數(shù)據(jù)的持久化

一、為什么使用文件

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

我們?cè)谙爰热皇峭ㄓ嶄浘蛻?yīng)該把信息記錄下來(lái),只有我們自己選擇刪除數(shù)據(jù)的時(shí)候,數(shù)據(jù)才不復(fù)存在。

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

二、什么是文件

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

2.1 程序文件

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

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

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

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

2.3 文件名

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

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

3.1 文件指針

緩沖文件系統(tǒng)中,關(guān)鍵的概念是“文件類型指針”,簡(jiǎn)稱“文件指針”。每個(gè)被使用的文件都在內(nèi)存中開辟了一個(gè)相應(yīng)的文件信息區(qū),用來(lái)存放文件的相關(guān)信息(如文件的名字,文件狀態(tài)及文件當(dāng)前的位置等)。這些信息是保存在一個(gè)結(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)容不完全相同,但是大同小異。
  • 每當(dāng)打開一個(gè)文件的時(shí)候,系統(tǒng)會(huì)根據(jù)文件的情況自動(dòng)創(chuàng)建一個(gè)FILE結(jié)構(gòu)的變量,并填充其中的信息,我們?cè)谑褂脮r(shí)不必關(guān)心其細(xì)節(jié)。
  • 一般都是通過一個(gè)FILE的指針來(lái)維護(hù)這個(gè)FILE結(jié)構(gòu)的變量,這樣使用起來(lái)更加方便。

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

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

??比如:

 

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

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

ANSIC 規(guī)定使用fopen函數(shù)來(lái)打開文件,fclose來(lái)關(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)存當(dāng)中的,而我們想把內(nèi)存當(dāng)中的數(shù)據(jù)放在文件當(dāng)中去,文件又是在硬盤上的,所以把內(nèi)存當(dāng)中的數(shù)據(jù)往硬盤上放的這個(gè)操作叫做寫文件或輸出操作,把文件當(dāng)中的數(shù)據(jù)往內(nèi)存里邊放的操作叫讀文件或輸入操作。

四、文件的順序讀寫

 

??深入理解 “流”:

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

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

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.功能:

向指定的文件流中寫入一個(gè)字符。

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;
}

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

??fgetc函數(shù): 

1.函數(shù)原型:

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

2.功能:

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

3.示例: 


 

程序運(yùn)行起來(lái)后,先打開文件,如果成功,就開始讀文件,讀文件的時(shí)候光標(biāo)默認(rèn)在最前面,當(dāng)fgetc讀一個(gè)字符的時(shí)候,光標(biāo)指向的那個(gè)位置為a,所以就返回字符a的ASCII值,然后打印在屏幕上,以同樣的步驟操作三次,就會(huì)將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:指向用于存儲(chǔ)讀取字符串的字符數(shù)組的指針。num:要讀取的最大字符數(shù)(num - 1個(gè))。stream:要從中讀取行的文件流。

2.功能:

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

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;}

因?yàn)樗x取的最大字符數(shù)是num - 1個(gè),所以只存儲(chǔ)了前兩個(gè)字符。 

 ??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:每個(gè)數(shù)據(jù)的字節(jié)數(shù)。
  • count:要寫入的數(shù)據(jù)塊的數(shù)量。
  • stream:要寫入數(shù)據(jù)的文件流。

2.功能:

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

3.示例: 

//二進(jìn)制的方式寫進(jìn)文件
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;
	}
	//二進(jìn)制的寫文件
	fwrite(arr, sizeof(arr[0]), sizeof(arr) / sizeof(arr[0]), pf);
 
	//關(guān)閉文件
	fclose(pf);
	pf = NULL;
 
	return 0;
}

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

fread函數(shù):

  1.函數(shù)原型:

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

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

2.功能:

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

3.示例: 

//二進(jìn)制的方式讀取文件
int main()
{
	int arr[10] = { 0 };
	//打開文件
	FILE* pf = fopen("text.txt", "rb");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//二進(jìn)制的讀文件
	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;
}

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

scanf、fscanf、sscanf

printf、fprintf、sprintf

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

fscanf是針對(duì)所有輸入流(文件流、標(biāo)準(zhǔn)輸入流)的格式化輸入函數(shù);sprintf是針對(duì)所有輸出流(文件流、標(biāo)準(zhǔn)輸出流)的格式化輸出函數(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;
}

 

五、文件的隨機(jī)讀寫

5.1 fseek函數(shù):

  1.函數(shù)原型:

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

stream:指向FILE對(duì)象的指針,它標(biāo)識(shí)了要定位的文件。

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

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

SEEK_SET:從文件開頭開始偏移。SEEK_CUR:從當(dāng)前位置開始偏移。SEEK_END:從文件末尾開始偏移。

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

2.功能:

 fseek函數(shù)用于設(shè)置文件位置指針,以便在文件中進(jìn)行定位。它可以將文件位置指針設(shè)置到文件的任意位置,從而可以進(jìn)行讀取或?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);//從當(dāng)前位置開始偏移
	//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)在我想從中讀取字符出來(lái),用fgetc函數(shù)就可以,但我想讓它第三個(gè)字符讀的是a,這個(gè)時(shí)候就可以用fseek函數(shù)。

5.2 ftell函數(shù):

1.函數(shù)原型: 

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

2. 功能: 

用于獲取文件位置指針的當(dāng)前位置,即返回當(dāng)前位置相對(duì)于文件開頭的偏移量。

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對(duì)象的指針,用于標(biāo)識(shí)要重新定位的文件。

2.功能:

用于將文件位置指針重新定位到文件的開頭,即相當(dāng)于調(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ìn)制文件

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

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

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


 

??測(cè)試代碼:

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

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

 

將10000轉(zhuǎn)換成二進(jìn)制為 0010 0111 0001 0000,這是16個(gè)二進(jìn)制位,不夠32位,我們給它補(bǔ)齊0000 0000 0000 0000 0010 0111 0001 0000,每4個(gè)二進(jìn)制位轉(zhuǎn)換成1個(gè)16進(jìn)制位,就為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é)束后,用來(lái)判斷文件是否因?yàn)樽x取過程中遇到錯(cuò)誤而結(jié)束。feof:在文件讀取結(jié)束后,用來(lái)判斷文件是否因?yàn)樽x取過程中遇到文件結(jié)束標(biāo)志而結(jié)束。牢記:在文件讀取過程中,不能用feof函數(shù)的返回值直接用來(lái)判斷文件是否結(jié)束。而是應(yīng)用于當(dāng)文件讀取結(jié)束的時(shí)候,判斷是讀取失敗結(jié)束,還是遇到文件尾結(jié)束 。

 示例:

#include <stdio.h>
#include <stdlib.h>
 
int main()
{
	int c; // 注意:是int而非char,因?yàn)橐筇幚鞥OF,而EOF實(shí)際是-1,是個(gè)整型值
	FILE* fp = fopen("test.txt", "r");
	if (!fp) 
	{
		perror("fopen");
		return 1;
	}
	//fgetc 當(dāng)讀取失敗的時(shí)候或者遇到文件結(jié)束的時(shí)候,都會(huì)返回EOF
	while ((c = fgetc(fp)) != EOF) // 標(biāo)準(zhǔn)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 二進(jìn)制文件的讀取結(jié)束判定

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

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

示例:

#include <stdio.h>
 
enum { SIZE = 5 };
int main()
{
	double a[SIZE] = { 1.,2.,3.,4.,5. };
	FILE* fp = fopen("test.bin", "wb"); // 必須用二進(jìn)制模式
	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 標(biāo)準(zhǔn)采用“緩沖文件系統(tǒng)”處理數(shù)據(jù)文件,所謂緩沖文件系統(tǒng)是指系統(tǒng)自動(dòng)地在內(nèi)存中為程序中每一個(gè)正在使用的文件開辟一塊“文件緩沖區(qū)”。從內(nèi)存向磁盤輸出數(shù)據(jù)會(huì)先送到內(nèi)存中的緩沖區(qū),裝滿緩沖區(qū)后才一起送到磁盤上。如果從磁盤向計(jì)算機(jī)讀入數(shù)據(jù),則從磁盤文件中讀取數(shù)據(jù)輸入到內(nèi)存緩沖區(qū)(充滿緩沖區(qū)),然后再?gòu)木彌_區(qū)逐個(gè)地將數(shù)據(jù)送到程序數(shù)據(jù)區(qū)(程序變量等),緩沖區(qū)的大小根據(jù)C編譯系統(tǒng)決定。

#include <stdio.h>
#include <windows.h>
 
//VS2019 WIN10環(huán)境測(cè)試
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ū)時(shí),才將輸出緩沖區(qū)的數(shù)據(jù)寫到文件(磁盤)
	//注:fflush 在高版本的VS上不能使用了
	printf("再睡眠10秒-此時(shí),再次打開test.txt文件,文件有內(nèi)容了\n");
	Sleep(10000);
	fclose(pf);
	//注:fclose在關(guān)閉文件的時(shí)候,也會(huì)刷新緩沖區(qū)
	pf = NULL;
	return 0;
}

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

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

相關(guān)文章

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

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

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

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

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

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

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

    C語(yǔ)言實(shí)現(xiàn)的統(tǒng)計(jì)素?cái)?shù)并求和代碼分享

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

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

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

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

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

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

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

    C語(yǔ)言簡(jiǎn)易版flappy bird小游戲

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

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

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

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

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

最新評(píng)論