C語言文件操作(超詳細(xì)版)-創(chuàng)新互聯(lián)

目錄

創(chuàng)新互聯(lián)建站主營寧晉網(wǎng)站建設(shè)的網(wǎng)絡(luò)公司,主營網(wǎng)站建設(shè)方案,重慶APP開發(fā),寧晉h5微信小程序開發(fā)搭建,寧晉網(wǎng)站營銷推廣歡迎寧晉等地區(qū)企業(yè)咨詢

什么是文件

?文件分類

程序文件

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

文件的使用

?文件指針

文件指針的使用

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

文件的使用方式

?文件的順序讀寫

1.寫入一個字符

2.讀取一個字符

3.連續(xù)每次讀取一個字符

4.覆蓋并寫入一行數(shù)據(jù)

5.讀取指定長度的數(shù)據(jù)

6.將結(jié)構(gòu)體信息寫入文件中

7.讀取文件信息到結(jié)構(gòu)體變量中

8.二進(jìn)制寫入文件

9.讀取二進(jìn)制文件信息

10.sscanf()函數(shù)、sprintf()函數(shù)

文件的隨機(jī)讀寫

?fseek()函數(shù)

?ftell函數(shù)()

??rewind()函數(shù)

二進(jìn)制文件和文本文件

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

?feof()函數(shù)

文本文件的判斷

二進(jìn)制文件的判斷



📌————本章重點————📌

🔗文件指針

🔗文件的順序讀寫

🔗文件的隨機(jī)讀寫

🔗文件讀取結(jié)束判定

?————————————?


什么是文件

與普通文件載體不同,文件是以硬盤為載體存儲在計算機(jī)上的信息集合,文件可以是文本文檔、圖片、程序等等。文件通常具有點+三個字母的文件擴(kuò)展名,用于指示文件類型(例如,圖片文件常常以KPEG格式保存并且文件擴(kuò)展名為.jpg)。

? 將數(shù)據(jù)放入文件中,相比代碼程序中堆棧上的數(shù)據(jù),其優(yōu)點在于可以隨時做到需要時添加、舍棄時刪除,數(shù)據(jù)可以持久化。

文件分類:

? 文件一般講兩種:程序文件和數(shù)據(jù)文件;

程序文件:

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

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

? 包括程序運(yùn)行時所讀寫的數(shù)據(jù)。本篇所涉及的就是數(shù)據(jù)文件。


文件的使用

文件的操作一般分三步:1.打開文件;2.讀/寫;3.關(guān)閉文件;

文件指針

? 想要對文件進(jìn)行操作,“文件指針”就是一個關(guān)鍵橋梁(亦名:文件類型指針);????????????????

底層原理:每個被使用的文件,都在內(nèi)存中開辟了一個相應(yīng)的文件信息區(qū),用來存放文件的相關(guān)信息(如:文件名、文件狀態(tài)、文件位置等),這些信息被保存到一個結(jié)構(gòu)體中,系統(tǒng)為其聲明為FILE,每當(dāng)打開一個文件的時候,系統(tǒng)就會根據(jù)情況自動創(chuàng)建一個FILE結(jié)構(gòu)的變量,并且通過FILE*的指針來維護(hù)這個結(jié)構(gòu)。

文件指針的使用:
FILE* pf;

定義一個文件指針變量pf,它可以指向某個文件的文件信息區(qū),通過其即可訪問到該文件。


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

在打開文件的同時,都會返回一個FILE*的指針變量指向該文件,也相當(dāng)于建立了指
針和文件的關(guān)系。

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

文件的使用方式:

按常用序:

使用方式作用?如果文件不存在
"r"(只讀)為了輸入數(shù)據(jù),打開一個已經(jīng)存在的文本文件出錯? ? ? ? ? ? ? ??
"w"(只寫)為了輸出數(shù)據(jù),打開一個文本文件建立一個新的文件
"a"(追加)向文本文件添加數(shù)據(jù)建立一個新的文件
"rb"(只讀)為了輸入數(shù)據(jù),打開一個二進(jìn)制文件出錯
"wb"(只寫)為了輸出數(shù)據(jù),打開一個二進(jìn)制文件建立一個新的文件
"ab"(追加)向一個二進(jìn)制文件尾添加數(shù)據(jù)出錯
"r+"(讀寫)為了讀和寫,打開一個文本文件出錯
"w+"(讀寫)為了讀和寫,建立一個新的文本文件建立一個新的文件
"a+"(讀寫)打開一個文本文件,在文件尾進(jìn)行讀寫建立一個文件
"rb+"(讀寫)為了讀和寫,打開一個二進(jìn)制文件出錯
"wb+"(讀寫)為了讀和寫,建立一個新的二進(jìn)制文件建立一個新的文件
"ab+"(讀寫)打開一個二進(jìn)制文件,在文件尾進(jìn)行讀寫建立一個新的文件

文件的順序讀寫
函數(shù)名功能適用性
fgetc()字符輸入函數(shù)所有輸入流
fputc()字符輸出函數(shù)所有輸出流
fgets()文本行輸入函數(shù)所有輸入流
fputs()文本行輸出函數(shù)所有輸出流
fscanf()格式化輸入函數(shù)所有輸入流
fprintf()格式化輸出函數(shù)所有輸出流
fread()二進(jìn)制輸入文件
fwrite()二進(jìn)制輸出文件

以上結(jié)合起來實例:

#include#include#includeint main()
{
	FILE* pf= fopen("test.txt", "w+");
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return;
	}
	//輸入一個字符
	fputc('a', pf);
	//用完關(guān)閉文件
	fclose(pf);
	pf = NULL;

	return 0;
}

如圖示:在源文件所在目錄下,原本沒有test.txt文件,是w+創(chuàng)建了這個新的文件,并寫入一個字符a?

1.寫入一個字符:
//寫文件    
    fputc('a', pf);

2.讀取一個字符:
//讀取一個字符
	int ch = fgetc(pf);
	if (ch != EOF)
	{
		printf("%c\n", ch);
	}

3.連續(xù)每次讀取一個字符:
//文件中有abcdefg

	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
	ch = fgetc(pf);
	printf("%c\n", ch);	//d

4.覆蓋并寫入一行數(shù)據(jù):
fputs("hello world", pf);

注意:這里fputs函數(shù)雖然是整行寫入,但會覆蓋掉原始數(shù)據(jù)、

5.讀取指定長度的數(shù)據(jù):
//定一一個數(shù)組
	char arr[10] = { 0 };
	fgets(arr, 5, pf);    //將所讀取的數(shù)據(jù)放入arr中
	printf("%s\n", arr);

6.將結(jié)構(gòu)體信息寫入文件中:

這里的結(jié)構(gòu)體信息就是格式化的,那么就需要fprintf()函數(shù)了

#includetypedef struct S
{
	char name[10];
	int age;

}Peo;
int main()
{
	FILE* pf = fopen("test.txt", "w");

	if (pf != NULL)
	{
		Peo p = { "zhangsan", 18 };
		fprintf(pf, "%s %d\n", p.name, p.age);

		fclose(pf);
		pf = NULL;
	}

	return 0;
}

7.讀取文件信息到結(jié)構(gòu)體變量中:
#includetypedef struct S
{
	char name[10];
	int age;

}Peo;
int main()
{
	FILE* pf = fopen("test.txt", "r");

	if (pf != NULL)
	{
		Peo p = { 0 };

		fscanf(pf, "%s %d", p.name, &p.age);

		printf("%s %d", p.name, p.age);

		fclose(pf);
		pf = NULL;
	}

	return 0;
}

8.二進(jìn)制寫入文件:
  • size_t fwrite( const void *buffer, size_tsize, size_tcount, FILE *stream);
#include#include#includetypedef struct S
{
	char name[10];
	int age;

}Peo;
int main()
{
	FILE* pf = fopen("test.txt", "wb+");

	if (pf != NULL)
	{
		Peo p = { "lisi", 19};

		fwrite(&p, sizeof(Peo), 1, pf);

		fclose(pf);
		pf = NULL;
	}

	return 0;
}

9.讀取二進(jìn)制文件信息:
  • size_t fread( void *buffer, size_tsize, size_tcount, FILE *stream);

#includetypedef struct S
{
	char name[10];
	int age;

}Peo;
int main()
{
	FILE* pf = fopen("test.txt", "rb+");

	if (pf != NULL)
	{
		Peo p = { 0 };

		fread(&p, sizeof(Peo), 1, pf);

		printf("%s %d\n", p.name, p.age);

		fclose(pf);
		pf = NULL;
	}

	return 0;
}

10.sscanf()函數(shù)、sprintf()函數(shù):

這兩個函數(shù)雖然和文件操作關(guān)系不大,但是容易與文件操作函數(shù)混淆;

  • sscanf()函數(shù):
  • int sscanf( const char *buffer, const char *format[,argument] ... );
  • 將一個字符串轉(zhuǎn)化為格式化數(shù)據(jù);
#includetypedef struct S
{
	char name[10];
	int age;

}Peo;
int main()
{
	//定義一個字符串
	char buffer[] = { "zhansan 19" };
	//定義一個結(jié)構(gòu)但不賦值
	Peo p = { 0 };

	sscanf(buffer, "%s %d", p.name, &p.age);

	return 0;
}

  • sprintf()函數(shù):
  • int sprintf( char *buffer, const char *format[,argument] ... );

  • 將一個格式化數(shù)據(jù)轉(zhuǎn)化為字符串;

#includetypedef struct S
{
	char name[10];
	int age;

}Peo;
int main()
{	
	//定義一個結(jié)構(gòu)
	Peo p = { "zhangsan",19};
	//定義一個字符串
	char buffer[50] = { 0 };

	sprintf(buffer, "%s %d\n", p.name, p.age);

	return 0;
}


文件的隨機(jī)讀寫

所謂的隨機(jī)讀寫,其實就是指定我們想要讀寫的位置。

fseek()函數(shù):
  • 該函數(shù)可以從定位位置的偏移量處開始讀寫;
  • int fseek( FILE *stream, long offset, int origin );
    文件流? ? ? ? ??偏移量? ? 起始位置?
  • 返回值:
  1. 如果成功,fseek返回0;
  2. 否則,它返回一個非零值;
  3. 在無法查找的設(shè)備上,返回值未定義;? ? ? ??

三種定位指針:

使用實例:

#include#include#includeint main()
{
	FILE* pf = fopen("test.txt", "r");

	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return;
	}
	//開始多次讀取
	//定位指針:比如要讀取從頭開始向后偏移 2 個單位的一個字符
	fseek(pf, 2, SEEK_SET);
	int ch = fgetc(pf);
	printf("%c\n", ch);

	//第二次讀取:要拿到當(dāng)前文件指針?biāo)幬恢孟蚝笃?個單位的字符
	fseek(pf, 5, SEEK_CUR);
	ch = fgetc(pf);
	printf("%c\n", ch);

	//第三次讀?。阂玫轿募髂┪蚕蚯捌?個單位的一個字符
	fseek(pf, -8, SEEK_END);
	ch = fgetc(pf);
	printf("%c\n", ch);

	fclose(pf);
	pf = NULL;

	return 0;
}

特別說明:

在每使用完一次fseek函數(shù)后,文件指針會自動向后移動一位:

ftell函數(shù)():
  • 該函數(shù)可以返回文件指針相對于起始位置的偏移量;
  • long int ftell ( FILE * stream );

使用實例:

我們直接在上一段代碼的基礎(chǔ)上加上ftell()函數(shù)即可直觀得到每次文件指針?biāo)幍奈恢茫?/p>

rewind()函數(shù):
  • 讓文件指針回到文件初始位置;
  • void rewind ( FILE * stream );

使用實例:


二進(jìn)制文件和文本文件

我們知道數(shù)據(jù)在內(nèi)存中是以二進(jìn)制形式存儲的,對于文件而言:如果不加轉(zhuǎn)換直接輸出到外存就是二進(jìn)制文件;如果要在外存上以ASCII碼形式存儲,就需要提前轉(zhuǎn)換最后以ASCII碼值形式存儲的文件就是文本文件。

對于字符,一律使用ASCII碼形式存儲,但對于數(shù)值型數(shù)據(jù),即可以使用ASCII碼存儲也可以使用二進(jìn)制形式存儲。

舉例:

數(shù)字10000的兩種存儲形式:

二進(jìn)制文件:

文本文件:

首先將10000分成'1','0','0','0','0',?這五個字符,用每個字符對應(yīng)的ASCII碼值進(jìn)行轉(zhuǎn)換:

由此可見:對于10000在數(shù),如果以二進(jìn)制形式存儲占用4個字節(jié),如果以ASCII碼存儲占用5個字節(jié)。試想:那對于數(shù)字1呢?

顯而易見,二進(jìn)制文件存儲和文本文件存儲對不同范圍的數(shù)字可以做到節(jié)省空間。

對二進(jìn)制文件深入理解:

#includeint main()
{
	FILE* pf = fopen("test.txt", "wb");
	int a = 10000;

	if (pf != NULL)
	{
		fwrite(&a, 4, 1, pf);

		fclose(pf);
		pf = NULL;
	}

	return 0;
}

對于上面這段代碼,我們知道是將數(shù)值10000放入了test.txt文件中,但我們無法直接看到它在文件中的真實值,于是使用vs的二進(jìn)制編輯器即可查看:



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

feof()函數(shù):

該函數(shù)被許多人錯誤用來判斷文件是否讀取結(jié)束,其實它的作用是判斷文件讀取結(jié)束的原因;

文件讀取結(jié)束有兩種情況:1.讀取過程中出現(xiàn)異常; 2.讀取到文件末尾;

要找出文件讀取是哪個原因,就分為以下情況:

文本文件:

  • 如果用 fgetc() 讀取,要判斷 feof() 的返回值是否為EOF;
  • 如果用 fgets() 讀取,要判斷 feof() 的返回值是否為NULL(0);

二進(jìn)制文件:

都是使用 fread() 讀取,要判斷其返回值與指定讀取個數(shù)的大小,如果小于實際要讀的個數(shù),就說明發(fā)生讀取異常,如果等于實際要讀的個數(shù),就說明是因讀取成功而結(jié)束;

對于讀取異常的判斷,我們考慮判斷 ferror() 函數(shù)的返回值:

  1. 若ferrror()為真——異常讀取而結(jié)束;
  2. 若feof()為真——正常讀取到尾而結(jié)束;

文本文件的判斷:
#include#include#includeint main()
{
	FILE* pf = fopen("test.txt", "r");

	if (pf == NULL)
	{
		perror("fopen is failed !");
		return;
	}
	int c = 0;
	//由于要檢查EOF——EOF本質(zhì)是0——所以是int
	while (c = fgetc(pf) != EOF)
	{
		putchar(c);
	}
	//直到while不執(zhí)行了—讀取結(jié)束了—判斷是什么原因結(jié)束的
	if (ferror(pf))
	{
		printf("讀取中出現(xiàn)錯誤\n");
	}
	else if (feof(pf))
	{
		printf("讀取到文件尾\n");
	}

	fclose(pf);
	pf = NULL;

	return 0;
}

二進(jìn)制文件的判斷:
#include#include#includeint main()
{
	FILE* pf = fopen("test.txt", "rb");
	int arr[5] = { 0 };

	if (pf == NULL)
	{
		return;
	}

	size_t num = fread(arr, sizeof(int), 5, pf);

	if (num == 5)
	{
		//說明全部讀取成功
		printf("Array read successfully\n");
	}
	else
	{
		//說明讀取不夠指定長度—判斷是什么原因
		if (ferror(pf))
		{
			printf("讀取中出現(xiàn)錯誤\n");
		}
		else if (feof(pf))
		{
			printf("讀取到文件尾\n");
		}
	}

	fclose(pf);
	pf = NULL;

	return 0;
}

你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級服務(wù)器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧

當(dāng)前名稱:C語言文件操作(超詳細(xì)版)-創(chuàng)新互聯(lián)
鏈接地址:http://bm7419.com/article16/hddgg.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供移動網(wǎng)站建設(shè)、網(wǎng)站導(dǎo)航電子商務(wù)、小程序開發(fā)手機(jī)網(wǎng)站建設(shè)、外貿(mào)網(wǎng)站建設(shè)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都app開發(fā)公司