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

一文帶你掌握C語(yǔ)言中的文件操作

 更新時(shí)間:2024年02月18日 10:19:29   作者:Betty’sSweet  
文件通常是駐留在外部介質(zhì)(如磁盤等)上的,在使用時(shí)才調(diào)入內(nèi)存中來(lái),本文主要來(lái)和大家介紹一下C語(yǔ)言中的文件操作,有需要的可以了解下

1. 什么是文件

文件其實(shí)是指一組相關(guān)數(shù)據(jù)的有序集合。這個(gè)數(shù)據(jù)集有一個(gè)名稱,叫做文件名。文件通常是駐留在外部介質(zhì)(如磁盤等)上的,在使用時(shí)才調(diào)入內(nèi)存中來(lái)。

從文件功能上來(lái)講,一般可分為:程序文件數(shù)據(jù)文件

1.1 文件名

一個(gè)文件要有一個(gè)唯一的文件標(biāo)識(shí),以便用戶識(shí)別和引用,這就是文件名

  • ?件名包含3部分:?件路徑+?件名主?+?件后綴
  • 例如:c:\code\test.txt

1.2 程序文件

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

源程序文件一般在創(chuàng)建程序目錄文件下

源程序文件經(jīng)過(guò)編譯器鏈接鏈接器鏈接可以生成我們的可執(zhí)行程序的文件。

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

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

本章討論的是數(shù)據(jù)文件。

以前各章所處理數(shù)據(jù)的輸?輸出都是以終端為對(duì)象的,即從終端的鍵盤輸?數(shù)據(jù),運(yùn)?結(jié)果顯?到顯?器上。

其實(shí)有時(shí)候我們會(huì)把信息輸出到磁盤上,當(dāng)需要的時(shí)候再?gòu)拇疟P上把數(shù)據(jù)讀取到內(nèi)存中使?,這?處理的就是磁盤上?件。

2. 文件的作用

如果沒(méi)有?件,我們寫的程序的數(shù)據(jù)是存儲(chǔ)在電腦的內(nèi)存中,如果程序退出,內(nèi)存回收,數(shù)據(jù)就丟失了,等再次運(yùn)?程序,是看不到上次程序的數(shù)據(jù)的,如果要將數(shù)據(jù)進(jìn)?持久化的保存,我們就需要使?文件。

3. 文件的打開(kāi)與關(guān)閉

3.1 流與標(biāo)準(zhǔn)流

(1) 流

我們程序的數(shù)據(jù)需要輸出到各種外部設(shè)備,也需要從外部設(shè)備獲取數(shù)據(jù),不同的外部設(shè)備的輸?輸出操作各不相同,為了?便程序員對(duì)各種設(shè)備進(jìn)??便的操作,我們抽象出了的概念,我們可以把流想象成流淌著字符的河。

C程序針對(duì)文件、畫面、 鍵盤等的數(shù)據(jù)輸?輸出操作都是通過(guò)流操作的。?般情況下,我們要想向流?寫數(shù)據(jù),或者從流中讀取數(shù)據(jù),都是要打開(kāi)流,然后操作。

(2) 標(biāo)準(zhǔn)流

那為什么我們從鍵盤輸?數(shù)據(jù),向屏幕上輸出數(shù)據(jù),并沒(méi)有打開(kāi)流呢?那是因?yàn)镃語(yǔ)?程序在啟動(dòng)的時(shí)候,默認(rèn)打開(kāi)了3個(gè)流:

• stdin-標(biāo)準(zhǔn)輸?流,在?多數(shù)的環(huán)境中從鍵盤輸?,scanf函數(shù)就是從標(biāo)準(zhǔn)輸?流中讀取數(shù)據(jù)。

• stdout-標(biāo)準(zhǔn)輸出流,?多數(shù)的環(huán)境中輸出?顯?器界?,printf函數(shù)就是將信息輸出到標(biāo)準(zhǔn)輸出流中。

• stderr-標(biāo)準(zhǔn)錯(cuò)誤流,?多數(shù)環(huán)境中輸出到顯?器界?。

這是默認(rèn)打開(kāi)了這三個(gè)流,我們使?scanf、printf等函數(shù)就可以直接進(jìn)?輸?輸出操作的。stdin、stdout、stderr三個(gè)流的類型是: FILE*,通常稱為文件指針。

在C語(yǔ)?中,就是通過(guò) FILE* 的?件指針來(lái)維護(hù)流的各種操作的。

3.2 文件指針

在緩沖文件系統(tǒng)中,關(guān)鍵的概念是“文件類型指針”,簡(jiǎn)稱“文件指針”。

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

例如,VS2022編譯環(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;
FILE* pf;//文件指針變量

不同的C編譯器的FILE類型包含的內(nèi)容不完全相同,但是大同小異。每當(dāng)打開(kāi)一個(gè)文件的時(shí)候,系統(tǒng)會(huì)根據(jù)文件的情況自動(dòng)創(chuàng)建一個(gè)FILE結(jié)構(gòu)的變量,并填充其中的信息,使用者不必關(guān)心細(xì)節(jié)。

一般都是通過(guò)一個(gè)FILE的指針來(lái)維護(hù)這個(gè)FILE結(jié)構(gòu)的變量,這樣使用起來(lái)更加方便。我們來(lái)看看如何創(chuàng)建一個(gè)FILE的指針變量

FILE* pf;	//文件指針變量

定義pf是一個(gè)指向FILE類型數(shù)據(jù)的指針變量??梢允筽f指向某個(gè)文件的文件信息區(qū)(是一個(gè)結(jié)構(gòu)體變量)。通過(guò)該文件信息區(qū)中的信息就能夠訪問(wèn)該文件。也就是說(shuō),通過(guò)文件指針變量能夠找到與它關(guān)聯(lián)的文件,以此來(lái)進(jìn)行相關(guān)操作。

3.3 文件的打開(kāi)與關(guān)閉

?件在讀寫之前應(yīng)該先打開(kāi)?件,在使?結(jié)束之后應(yīng)該關(guān)閉?件。這與我們前面學(xué)習(xí)的動(dòng)態(tài)內(nèi)存開(kāi)辟很類似。

在編寫程序的時(shí)候,在打開(kāi)?件的同時(shí),都會(huì)返回?個(gè)FILE*的指針變量指向該?件,也相當(dāng)于建?了指針和?件的關(guān)系。

ANSIC規(guī)定使? fopen 函數(shù)來(lái)打開(kāi)?件, fclose 來(lái)關(guān)閉?件。

(1) fopen函數(shù)

頭文件#include<stdio.h>

聲明:FILE *fopen(const char *filename, const char *mode)

  • filename -- 字符串,表示要打開(kāi)的文件名稱。
  • mode -- 字符串,表示文件的訪問(wèn)模式。

作用:使用給定的模式 mode 打開(kāi) filename 所指向的文件

返回值:該函數(shù)返回一個(gè) FILE 指針。否則返回 NULL,且設(shè)置全局變量 errno 來(lái)標(biāo)識(shí)錯(cuò)誤。

下表為常見(jiàn)的訪問(wèn)模式(mode):

文件使用方式含義如果指定文件不存在
“r”(只讀)為了輸入數(shù)據(jù),打開(kāi)一個(gè)已經(jīng)存在的文本文件出錯(cuò)
“w”(只寫)為了輸出數(shù)據(jù),打開(kāi)一個(gè)文本文件建立一個(gè)新的文件
“a”(追加)向文本文件尾添加數(shù)據(jù)建立一個(gè)新的文件
rb”(只讀)為了輸入數(shù)據(jù),打開(kāi)一個(gè)二進(jìn)制文件出錯(cuò)
“wb”(只寫)為了輸出數(shù)據(jù),打開(kāi)一個(gè)二進(jìn)制文件建立一個(gè)新的文件
“ab”(追加)向一個(gè)二進(jìn)制文件尾添加數(shù)據(jù)出錯(cuò)
“r+”(讀寫)為了讀和寫,打開(kāi)一個(gè)文本文件出錯(cuò)
“w+”(讀寫)為了讀和寫,建議一個(gè)新的文件建立一個(gè)新的文件
“a+”(讀寫)打開(kāi)一個(gè)文件,在文件尾進(jìn)行讀寫建立一個(gè)新的文件
“rb+”(讀寫)為了讀和寫打開(kāi)一個(gè)二進(jìn)制文件出錯(cuò)
“wb+”(讀寫)為了讀和寫,新建一個(gè)新的二進(jìn)制文件建立一個(gè)新的文件
“a+”(讀寫)打開(kāi)一個(gè)二進(jìn)制文件,在文件尾進(jìn)行讀寫建立一個(gè)新的文件

(2) fclose函數(shù)

頭文件#include<stdio.h>

聲明:int fclose(FILE *stream)

stream -- 這是指向 FILE 對(duì)象的指針,該 FILE 對(duì)象指定了要被關(guān)閉的流。

作用:關(guān)閉流 stream。刷新所有的緩沖區(qū)

返回值:如果流成功關(guān)閉,則該方法返回零。如果失敗,則返回 EOF。

下列是fopen與fclose具體使用:

int main()
{
	//打開(kāi)文件
	FILE* pf = fopen("test.txt", "w");
	if (pf == NULL)
	{
		perror(" fopen fail");
		return 1;
	}	
	//關(guān)閉文件
	fclose(pf);
	pf = NULL;		//防止野指針
	return 0;
}

4. 文件的順序讀寫

4.1 單字符輸入輸出

(1) fputc函數(shù)

頭文件:#include<stdio.h>

聲明:int fputc(int char, FILE *stream)

  • char -- 這是要被寫入的字符。該字符以其對(duì)應(yīng)的 int 值進(jìn)行傳遞。
  • stream -- 這是指向 FILE 對(duì)象的指針,該 FILE 對(duì)象標(biāo)識(shí)了要被寫入字符的流。

作用:把參數(shù) char 指定的字符(一個(gè)無(wú)符號(hào)字符)寫入到指定的流 stream 中。

返回值:如果沒(méi)有發(fā)生錯(cuò)誤,則返回被寫入的字符。如果發(fā)生錯(cuò)誤,則返回 EOF,并設(shè)置錯(cuò)誤標(biāo)識(shí)符。

下列是具體的fputc的使用方法:

#include<stdio.h>
int main()
{
	//打開(kāi)文件
	FILE* pf = fopen("test.txt", "w");
	if (pf == NULL)
	{
		perror(" fopen fail");
		return 1;
	}
    //將abc放進(jìn)文件
	fputc('a', pf);
	fputc('b', pf);
	fputc('c', pf);
	//關(guān)閉文件
	fclose(pf);
	pf = NULL;//防止野指針
	return 0;
}

如果你想查看寫入結(jié)果,可以在創(chuàng)建項(xiàng)目下找到Debug文件,打開(kāi)

(2) fgetc函數(shù)

頭文件:#include<stdio.h>

聲明:int fgetc(FILE *stream)

  • stream -- 這是指向 FILE 對(duì)象的指針,該 FILE 對(duì)象標(biāo)識(shí)了要在上面執(zhí)行操作的流。

作用:從指定的流 stream 獲取下一個(gè)字符(一個(gè)無(wú)符號(hào)字符)。

返回值:該函數(shù)以無(wú)符號(hào) char 強(qiáng)制轉(zhuǎn)換為 int 的形式返回讀取的字符,如果到達(dá)文件末尾或發(fā)生讀錯(cuò)誤,則返回 EOF。

下列是具體的fputc的使用方法:

#include<stdio.h>
int main()
{
	//打開(kāi)文件
	FILE* pf = fopen("test.txt", "r");//只讀
	if (pf == NULL)
	{
		perror(" fopen fail");
		return 1;
	}
	fputc('a', pf);
	fputc('b', pf);
	fputc('c', pf);
	int ch = fgetc(pf);
	printf("讀出來(lái)的字符為:%c\n", ch);
	ch = fgetc(pf);
	printf("讀出來(lái)的字符為:%c\n", ch);
	ch = fgetc(pf);
	printf("讀出來(lái)的字符為:%c\n", ch);
	//關(guān)閉文件
	fclose(pf);
	pf = NULL;//防止野指針
	return 0;
}

輸出結(jié)果:

4.2 文本行輸入輸出

(1) fputs函數(shù)

頭文件:#include<stdio.h>

聲明:int fputs(const char *str, FILE *stream)

  • str -- 這是一個(gè)數(shù)組,包含了要寫入的以空字符終止的字符序列。
  • stream -- 這是指向 FILE 對(duì)象的指針,該 FILE 對(duì)象標(biāo)識(shí)了要被寫入字符串的流。

作用:把字符串寫入到指定的流 stream 中,但不包括空字符

返回值:該函數(shù)返回一個(gè)非負(fù)值,如果發(fā)生錯(cuò)誤則返回 EOF。

下面是fputs的具體使用方法:

#include<stdio.h>
int main()
{
	//打開(kāi)文件
	FILE* pf = fopen("test.txt", "w");
	if (pf == NULL)
	{
		perror(" fopen fail");
		return 1;
	}
	fputs("hello betty", pf);
	//關(guān)閉文件
	fclose(pf);
	pf = NULL;//防止野指針
	return 0;
}

演示結(jié)果:

(2) fgets函數(shù)

頭文件:#include<stdio.h>

聲明:char *fgets(char *str, int n, FILE *stream)

  • str -- 這是指向一個(gè)字符數(shù)組的指針,該數(shù)組存儲(chǔ)了要讀取的字符串。
  • n -- 這是要讀取的最大字符數(shù)(包括最后的空字符)。通常是使用以 str 傳遞的數(shù)組長(zhǎng)度。
  • stream -- 這是指向 FILE 對(duì)象的指針,該 FILE 對(duì)象標(biāo)識(shí)了要從中讀取字符的流。

作用:從指定的流 stream 讀取一行,并把它存儲(chǔ)在 str 所指向的字符串內(nèi)。當(dāng)讀取 (n-1) 個(gè)字符時(shí),或者讀取到換行符時(shí),或者到達(dá)文件末尾時(shí),它會(huì)停止,具體視情況而定。

返回值:如果成功,該函數(shù)返回相同的 str 參數(shù)。如果到達(dá)文件末尾或者沒(méi)有讀取到任何字符,str 的內(nèi)容保持不變,并返回一個(gè)空指針。如果發(fā)生錯(cuò)誤,返回一個(gè)空指針。

下面是fgets的具體使用方法:

#include<stdio.h>
int main()
{
	//打開(kāi)文件
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror(" fopen fail");
		return 1;
	}
	fputs("hello betty", pf);
	char arr[] = "##########";
	fgets(arr, 5, pf);
	puts(arr);
	//關(guān)閉文件
	fclose(pf);
	pf = NULL;//防止野指針
	return 0;
}

輸出結(jié)果:

雖然讀取五個(gè)字符,但是只會(huì)顯示四個(gè)字符,因?yàn)?code>'\0也會(huì)默認(rèn)添加進(jìn)去

4.3 格式化輸入輸出

(1) fprintf函數(shù)

頭文件:#include<stdio.h>

聲明:int fprintf(FILE *stream, const char *format, ...)

  • stream -- 這是指向 FILE 對(duì)象的指針,該 FILE 對(duì)象標(biāo)識(shí)了流。
  • format -- 這是 C 字符串,包含了要被寫入到流 stream 中的文本。它可以包含嵌入的 format 標(biāo)簽,format 標(biāo)簽可被隨后的附加參數(shù)中指定的值替換,并按需求進(jìn)行格式化。

作用:按照一定格式向輸出流輸出數(shù)據(jù)。

返回值:如果成功,則返回寫入的字符總數(shù),否則返回一個(gè)負(fù)數(shù)。

下面是fprintf的具體使用方法:

typedef struct student {
	char name[20];
	int height;
	float score;
}stu;
int main()
{
	stu s = { "beidi", 170, 95.0 };
	//寫文件
	FILE* pf = fopen("test.txt", "w");
	if (pf == NULL)
	{
		perror(" fopen fail");
		return 1;
	}
	fprintf(pf, "%s %d %f", s.name, s.height, s.score);
	//關(guān)閉文件
	fclose(pf);
	pf = NULL;//防止野指針
	return 0;
}

(2) fscanf函數(shù)

頭文件:#include<stdio.h>

聲明:int fscanf(FILE *stream, const char *format, ...)

  • stream -- 這是指向 FILE 對(duì)象的指針,該 FILE 對(duì)象標(biāo)識(shí)了流。
  • format -- 這是 C 字符串,包含了以下各項(xiàng)中的一個(gè)或多個(gè):空格字符、非空格字符和 format說(shuō)明符。

作用:按照一定格式從輸入流輸入數(shù)據(jù)。

返回值:如果成功,該函數(shù)返回成功匹配和賦值的個(gè)數(shù)。如果到達(dá)文件末尾或發(fā)生讀錯(cuò)誤,則返回 EOF。

下面是fscanf的具體使用方法:

typedef struct student {
	char name[20];
	int height;
	float score;
}stu;
int main()
{
	stu s = { "beidi", 170, 95.0 };
	//寫文件
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror(" fopen fail");
		return 1;
	}
	fscanf(pf, "%s %d %f", s.name, &(s.height), &(s.score));
	printf("%s %d %f", s.name, s.height, s.score);
	//關(guān)閉文件
	fclose(pf);
	pf = NULL;//防止野指針
	return 0;
}

4.4 二進(jìn)制輸入輸出

(1) fwrite函數(shù)

頭文件:#include<stdio.h>

聲明:size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)

  • ptr -- 這是指向要被寫入的元素?cái)?shù)組的指針。
  • size -- 這是要被寫入的每個(gè)元素的大小,以字節(jié)為單位。
  • nmemb -- 這是元素的個(gè)數(shù),每個(gè)元素的大小為 size 字節(jié)。
  • stream -- 這是指向 FILE 對(duì)象的指針,該 FILE 對(duì)象指定了一個(gè)輸出流。

作用:把 ptr 所指向的數(shù)組中的數(shù)據(jù)寫入到給定流 stream 中。

返回值:如果成功,該函數(shù)返回一個(gè) size_t 對(duì)象,表示元素的總數(shù),該對(duì)象是一個(gè)整型數(shù)據(jù)類型。如果該數(shù)字與 nmemb 參數(shù)不同,則會(huì)顯示一個(gè)錯(cuò)誤。

下面是fwrite的具體使用方法:

typedef struct student {
	char name[20];
	int height;
	float score;
}stu;
int main()
{
	stu s = { "beidi", 170, 95.0 };
	//寫文件
	FILE* pf = fopen("test.txt", "wb");//二進(jìn)制寫入
	if (pf == NULL)
	{
		perror(" fopen fail");
		return 1;
	}
	fwrite(&s, sizeof(s), 1, pf);
	//關(guān)閉文件
	fclose(pf);
	pf = NULL;//防止野指針
	return 0;
}

二進(jìn)制數(shù)據(jù)正常人是無(wú)法看懂的,但是電腦能準(zhǔn)確識(shí)別

(2) fread函數(shù)

頭文件:#include<stdio.h>

聲明:size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)

  • ptr -- 這是指向帶有最小尺寸 size*nmemb 字節(jié)的內(nèi)存塊的指針。
  • size -- 這是要讀取的每個(gè)元素的大小,以字節(jié)為單位。
  • nmemb -- 這是元素的個(gè)數(shù),每個(gè)元素的大小為 size 字節(jié)。
  • stream -- 這是指向 FILE 對(duì)象的指針,該 FILE 對(duì)象指定了一個(gè)輸入流。

作用:從給定流 stream 讀取數(shù)據(jù)到 ptr 所指向的數(shù)組中

返回值:成功讀取的元素總數(shù)會(huì)以 size_t 對(duì)象返回,size_t 對(duì)象是一個(gè)整型數(shù)據(jù)類型。如果總數(shù)與 nmemb 參數(shù)不同,則可能發(fā)生了一個(gè)錯(cuò)誤或者到達(dá)了文件末尾。

下面是fread的具體使用方法

typedef struct student {
	char name[20];
	int height;
	float score;
}stu;
int main()
{
	stu s = {0};
	//寫文件
	FILE* pf = fopen("test.txt", "rb");//二進(jìn)制寫出
	if (pf == NULL)
	{
		perror(" fopen fail");
		return 1;
	}
	fread(&s, sizeof(s), 1, pf);
	printf("%s %d %f", s.name, s. height, s.score);
	//關(guān)閉文件
	fclose(pf);
	pf = NULL;//防止野指針
	return 0;
}

4.5 流輸入輸出

從前面我們知道在我們輸入輸出時(shí),默認(rèn)打開(kāi)**stdin - 標(biāo)準(zhǔn)輸入流 **, stdout - 標(biāo)準(zhǔn)輸出流, **stderr - 標(biāo)準(zhǔn)輸錯(cuò)誤 **。那我們可不可以利用流來(lái)輸入輸出呢?答案自然是可以的,下面是具體實(shí)例:

int main()
{
	printf("輸入前:");
	int ch = fgetc(stdin);//輸入
	printf("輸入后:");
	fputc(ch, stdout);//輸出
	return 0;
}

還有另外一種方法:

int main()
{
	printf("輸入前:");
	int ch = 0;
	fscanf(stdin, "%c", &ch);
	printf("輸入后:");
	fprintf(stdout, "%c", ch);
	return 0;
}

4.6 補(bǔ)充

(1) sprintf與sscanf

頭文件:#include<stdio.h>

聲明:int sprintf(char *str, const char *format, ...)

  • str -- 這是指向一個(gè)字符數(shù)組的指針,該數(shù)組存儲(chǔ)了 C 字符串。
  • format -- 這是字符串,包含了要被寫入到字符串 str 的文本。它可以包含嵌入的 format 標(biāo)簽,format 標(biāo)簽可被隨后的附加參數(shù)中指定的值替換,并按需求進(jìn)行格式化

作用:將格式化數(shù)據(jù)轉(zhuǎn)換為字符串

返回值:如果成功,則返回寫入的字符總數(shù),不包括字符串追加在字符串末尾的空字符。如果失敗,則返回一個(gè)負(fù)數(shù)。

頭文件:#include<stdio.h>

聲明:int sscanf(const char *str, const char *format, ...)

  • str -- 這是 C 字符串,是函數(shù)檢索數(shù)據(jù)的源。
  • format -- 這是 C 字符串,包含了以下各項(xiàng)中的一個(gè)或多個(gè):空格字符非空格字符和 format說(shuō)明符。

作用:將字符串按照一定格式轉(zhuǎn)換為格式化數(shù)據(jù)

返回值:如果成功,該函數(shù)返回成功匹配和賦值的個(gè)數(shù)。如果到達(dá)文件末尾或發(fā)生讀錯(cuò)誤,則返回 EOF。

下列展示了sprintf與sscanf的具體用法:

typedef struct student {
	char name[20];
	int height;
	float score;
}stu;

int main()
{
	char buf[100] = { 0 };
	stu s = { "betty", 170, 95.0f };
	stu tmp = { 0 };
	//將這個(gè)結(jié)構(gòu)體的成員轉(zhuǎn)化為字符串
	sprintf(buf, "%s %d %f", s.name, s.height, s.score);
	printf("%s\n", buf);
	//將這個(gè)字符串中內(nèi)容還原為一個(gè)結(jié)構(gòu)體數(shù)據(jù)呢
	sscanf(buf, "%s %d %f", tmp.name, &(tmp.height), &(tmp.score));
	printf("%s %d %f", tmp.name, tmp.height, tmp.score);
	return 0;
}

(2) 對(duì)比

下表展示了scanf與printf,fscanf與fprintf,sscanf與sprintf之間的區(qū)別

函數(shù)功能
scanf針對(duì)標(biāo)準(zhǔn)輸入(鍵盤)的格式化輸入函數(shù)
printf針對(duì)標(biāo)準(zhǔn)輸入出(屏幕)的格式化輸出函數(shù)
fscanf針對(duì)所以輸入流的格式化輸入函數(shù)
fprintf針對(duì)所以輸出流的格式化輸出函數(shù)
sscanf從一個(gè)字符串中讀取一個(gè)格式化數(shù)據(jù)
sprintf把一個(gè)格式化數(shù)據(jù)轉(zhuǎn)換為字符串

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

根據(jù)數(shù)據(jù)的組織形式,數(shù)據(jù)?件被稱為?本?件或者二進(jìn)制?件。

  • 文本文件:以ASCII字符的形式存儲(chǔ)的?件
  • 二進(jìn)制文件:數(shù)據(jù)在內(nèi)存中以?進(jìn)制的形式存儲(chǔ)的文件

?個(gè)數(shù)據(jù)在?件中是怎么存儲(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é)。

字符1的二進(jìn)制序列:00110001,字符0的二進(jìn)制序列:00110000

測(cè)試代碼:

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

右擊源文件,添加現(xiàn)有項(xiàng),將test.txt添加進(jìn)入

右擊test.txt文件,選擇打開(kāi)方式,選擇二進(jìn)制編輯器

10 27 00 00便是10000以小端存儲(chǔ)的十六進(jìn)制形式。

6. 文件的隨機(jī)讀寫

6.1 fseek函數(shù)

頭文件:#include<stdio.h>

聲明:int fseek(FILE *stream, long int offset, int whence)

  • stream -- 這是指向 FILE 對(duì)象的指針,該 FILE 對(duì)象標(biāo)識(shí)了流。
  • offset -- 這是相對(duì) whence 的偏移量,以字節(jié)為單位。
  • whence -- 這是表示開(kāi)始添加偏移 offset 的位置。

作用:設(shè)置流 stream 的文件位置為給定的偏移 offset,參數(shù) offset 意味著從給定的 whence 位置查找的字節(jié)數(shù)。

返回值:如果成功,則該函數(shù)返回零,否則返回非零值。

whence偏移offset的三種位置:

常量描述
SEEK_SET文件的開(kāi)頭
SEEK_CUR文件指針的當(dāng)前位置
SEEK_END文件的末尾

假設(shè)文件中放的是字符串“abcdef,下面是fseek的具體使用實(shí)例:

int main()
{
	//打開(kāi)文件
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror(" fopen fail");
		return 1;
	}
	fseek(pf, 4, SEEK_SET);
	//從其實(shí)位置偏移四個(gè)字節(jié)
	int ch1 = fgetc(pf);
	printf("%c ", ch1);
	fseek(pf, -3, SEEK_END);
	//從結(jié)束位置偏移七個(gè)個(gè)字節(jié)
         int ch2 = fgetc(pf);
	printf("%c ", ch2);
	fseek(pf, 1, SEEK_CUR);
	//從當(dāng)前位置偏移一個(gè)字節(jié)
	int ch3 = fgetc(pf);
	printf("%c ", ch3);
	//關(guān)閉文件
	fclose(pf);
	pf = NULL;//防止野指針
	return 0;
}

  • 從起始位置偏移四個(gè)字節(jié),輸出e。
  • 從末尾偏移三個(gè)字節(jié),輸出d。
  • 此時(shí)偏移指向e的位置,再偏移一個(gè)字節(jié)指向f。

6.2 ftell函數(shù)

頭文件:#include<stdio.h>

聲明:long int ftell(FILE *stream)

stream -- 這是指向 FILE 對(duì)象的指針,該 FILE 對(duì)象標(biāo)識(shí)了流。

作用:返回?件指針相對(duì)于起始位置的偏移量

返回值:該函數(shù)返回位置標(biāo)識(shí)符的當(dāng)前值。如果發(fā)生錯(cuò)誤,則返回 -1L,全局變量 errno 被設(shè)置為一個(gè)正值。

我們可以利用fseek和ftell來(lái)計(jì)算文件的長(zhǎng)度(不包含'\0'),下列是代碼示例

int main()
{
	FILE* pFile;
	long size;
	pFile = fopen("test.txt", "rb");
	if (pFile == NULL) 
		perror("Error opening file");
	else
	{
		fseek(pFile, 0, SEEK_END); //non-portable
		size = ftell(pFile);
		fclose(pFile);
		printf("文件長(zhǎng)度為: %ld bytes.\n", size);
	}
	return 0;
}

6.3 rewind函數(shù)

頭文件:#include<stdio.h>

聲明:void rewind(FILE *stream)

stream -- 這是指向 FILE 對(duì)象的指針,該 FILE 對(duì)象標(biāo)識(shí)了流

作用:讓?件指針的位置回到?件的起始位置

返回值:該函數(shù)不返回任何值。

rewind常常在文件讀與寫同時(shí)使用時(shí),以方便文件讀取。下面是rewind的具體使用實(shí)例:

#include <stdio.h>
int main()
{
	int n;
	FILE* pFile;
	char buffer[27];
	pFile = fopen("myfile.txt", "w+");
	for (n = 'A'; n <= 'Z'; n++)
		fputc(n, pFile);//放入26個(gè)字母
	rewind(pFile);//回到起始位置,方便讀取
	fread(buffer, 1, 26, pFile);//讀取·
	fclose(pFile);
	buffer[26] = '\0';//字符串的結(jié)束標(biāo)識(shí)
	printf(buffer);
	return 0;
}

7. ?件讀取結(jié)束的判定

7.1 被錯(cuò)誤使用的 feof

在我們學(xué)習(xí)C語(yǔ)言文件操作的過(guò)程中,常常會(huì)有人誤認(rèn)為feof是判斷文件是否結(jié)束的函數(shù),其實(shí)這并不準(zhǔn)確。feof 的作?是:當(dāng)?件讀取結(jié)束的時(shí)候,判斷是讀取結(jié)束的原因是:遇到?件尾結(jié)束還是文件讀取失敗結(jié)束。

7.2 常見(jiàn)的結(jié)束標(biāo)志

函數(shù)結(jié)束標(biāo)志
fgetc如果讀取正常,返回讀取到的字符的ASCLL碼值 如果讀取失敗,返回EOF
fgets如果讀取正常,返回讀取到的數(shù)據(jù)的地址 如果讀取失敗,返回NULL
fscanf如果讀取正常,返回的是格式串中指定的數(shù)據(jù)個(gè)數(shù) 如果讀取失敗,返回的是小于格式串中指定的數(shù)據(jù)個(gè)數(shù)
fread如果讀取正常,返回的是等于要讀取的數(shù)據(jù)個(gè)數(shù) 如果讀取失敗,返回的是小于要讀取的數(shù)據(jù)個(gè)數(shù)

8. 文件緩沖區(qū)

ANSIC 標(biāo)準(zhǔn)采用緩沖文件系統(tǒng)處理的數(shù)據(jù)文件的,所謂緩沖文件系統(tǒng)是指系統(tǒng)自動(dòng)地在內(nèi)存中為程序中每一個(gè)正在使用的文件開(kāi)辟一塊“文件緩沖區(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)決定的。

我們可以利用下列代碼證明緩沖區(qū)的存在:

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

刷新緩沖區(qū)前:

刷新緩沖區(qū)后:

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

以上就是一文帶你掌握C語(yǔ)言中的文件操作的詳細(xì)內(nèi)容,更多關(guān)于C語(yǔ)言文件操作的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論