C語言——文件

1.文件概述

“文件”是指一組相關數據的有序集合。這個數據集有一個名稱,叫做文件名。通常情況下,使用計算機也就是在使用文件。在之前我們學習了輸入和輸出,即從標準輸入設備(鍵盤)輸入,由標準輸出設備(顯示器或打印機)輸出。不僅如此,我們也常把磁盤作爲信息載體,用於保存中間結果或最終數據。在使用一些文字處理工具時,會打開一個文件將磁盤的信息輸入到內存,通過關閉一個文件來實現將內存數據輸出到磁盤。這時的輸入和輸出是針對文件系統的,所以說文件系統也是輸入和輸出的對象。

文件可以分爲文本文件二進制文件

文本文件:也成爲ASCII文件。這種文件在保存時,每個字符對應一個字節,用於存放對應的ASCII碼。
二進制文件:不是保存ASCII碼,而是按二進制的編碼方式來保存文件內容。

在C語言中,文件操作都是由庫函數來完成的。

2. 文件基本操作

文件基本操作包括文件的打開與關閉。除了標準的輸入、輸出文件外,其他所有的文件都必須先打開後使用,而使用後也必須關閉該文件。

2.1 文件指針
文件指針是一個指向文件有關信息的指針,這些信息包括文件名、狀態和當前位置,它保存在一個結構體變量裏。在使用文件時需要在內存中爲其分配空間,用來存放文件的基本信息。該結構體類型是由系統定義的,C語言規定該類型爲FILE型,其聲明如下:

typedef struct
{
	short level;
	unsigned flags;
	char fd;
	unsigned char hold;
	short bsize;
	unsigned char* buffer;
	unsigned char* curp;
	unsigned istemp;
	short token;
}FILE;

2.2 文件的打開
fopen函數用來打開一個文件,打開文件的操作就是創建一個流。

#include <stdio.h>
FILE* fp;
fp = fopen(文件名, 使用文件方式);

打開文件成功,則返回一個有確定指向的FILE類型指針;否則返回NULL。
在這裏插入圖片描述
例如,如果要以讀方式打開文件名爲123的文本文檔文件,應寫成如下形式:

FILE* fp;
fp = fopen("123.txt", "r");

2.3 文件的關閉
文件在使用完畢後,應使用fclose函數將其關閉。

#include <stdio.h>
fclose(文件指針);

當正常關閉時返回0;否則返回EOF.
例如:

fclose(fp);

注意:在程序結束之前應關閉所有文件,這樣做的目的是防止因爲沒有關閉而造成數據的流失。

3.文件的讀寫

3.1 fputc函數

ch = fputc(ch, fp);

該函數作用是把一個字符寫到磁盤文件(fp所指向的文件)中去。其中ch是要輸出的字符。如果函數輸出成功,則返回就是輸出的字符;否則返回EOF.

例:編程實現向E:\123.txt中寫入“Hello, C file!”,以"#"結束。

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>

int main()
{
	FILE* fp;
	char ch;
	if ((fp = fopen("E:\\123.txt", "w")) == NULL) /*以只讀方式打開*/
	{
		printf("無法打開文件!\n");
		return 0;
	}
	ch = getchar();
	while (ch != '#')
	{
		fputc(ch, fp);
		ch = getchar();
	}
	fclose(fp);
	return 0;
}

運行結果:
在這裏插入圖片描述
在這裏插入圖片描述
3.2 fgetc函數
該函數作用是從指定的文件(fp所指的文件)讀入一個字符給ch。需要注意的是,該文件必須是以讀或寫的方式打開。當遇到文件結束符時返回EOF.

ch=fgetc(fp);

例:編程,要求將E:\123.txt文件中的內容在屏幕上線束出來。

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>

int main()
{
	FILE* fp;
	char ch;
	fp = fopen("E:\\123.txt", "r");
	ch = fgetc(fp);  /*fgetc函數帶回一個字符給ch*/
	while (ch != EOF)
	{
		putchar(ch);  /*將讀入的字符輸出在屏幕上*/
		ch = fgetc(fp);  /*繼續讀字符*/
	}
	system("pause");
	return 0;
}

運行結果:
在這裏插入圖片描述

3.3 fputs函數
fputs函數與fputc函數類似,區別在於fputc函數每次只向文件寫入一個字符,而fputs函數每次向文件中寫入一個字符串。

fputs(字符串, 文件指針);

例:向指定的磁盤文件中寫入:“Hello, C language!”

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>

int main()
{
	FILE* fp;
	char filename[30], str[30];
	printf("請輸入文件名: \n");
	scanf("%s", filename);
	if ((fp = fopen(filename, "w")) == NULL)  /*判斷文件是否打開失敗*/
	{
		printf("文件打開失敗!\n");
		return 0;
	}
	printf("請輸入字符串: \n");
	getchar();
	gets(str);
	fputs(str, fp); /*將輸入的字符串寫入到fp所指向的文件中*/
	fclose(fp);
	return 0;
}

運行結果:
在這裏插入圖片描述
在這裏插入圖片描述
3.4 fgets函數
fgets函數與fgetc函數類似,區別在於fgetc函數每次從文件中讀出一個字符,而fgets函數每次從文件中讀出一個字符串。

fgets(字符數組名,n,文件指針);

該函數的作用是從指定的文件讀一個字符串到字符數組中。n表示所得到的字符串中字符的個數(包含"\0").

例:讀取任意磁盤文件中的內容。

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>

int main()
{
	FILE* fp;
	char filename[30], str[30];
	printf("請輸入文件名: ");
	scanf("%s", filename);
	if ((fp = fopen(filename, "r")) == NULL) /*判斷文件是否打開失敗*/
	{
		printf("文件打開失敗!\n");
		system("pause");
		return 0;
	}
	fgets(str, sizeof(str), fp); /*讀取磁盤文件中的內容*/
	printf("%s\n", str);   /*輸出到屏幕*/
	fclose(fp);
	system("pause");
	return 0;
}

運行結果:
在這裏插入圖片描述
在這裏插入圖片描述
3.5 fprintf函數
fprintf函數與printf函數作用相似,但它們最大的區別就是操作的對象不同。fprintf函數讀寫的對象不是終端而是磁盤文件。
fprintf函數的一般形式如下:

ch = fprintf(文件類型指針,格式字符串,輸出列表);

例如: fprintf(fp, “%d”, i);
它的作用是將整型變量i的值以"%d"的格式輸出到fp指向的文件中。

例:將數字97以字符的形式寫到磁盤文件中。

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>

int main()
{
	FILE* fp;
	int i = 97;   /*97對應的字符爲a*/
	char filename[30];
	printf("請輸入文件名: ");
	scanf("%s", filename);
	if ((fp = fopen(filename, "w")) == NULL) /*判斷文件是否打開失敗*/
	{
		printf("無法打開文件!\n");
		system("pause");
		return 0;
	}
	fprintf(fp, "%c", i); /*將97以字符形式寫入fp所指向的文件中*/
	fclose(fp);
	return 0;
}

運行結果:
在這裏插入圖片描述
在這裏插入圖片描述
3.6 fscanf函數
fscanf函數的一般形式如下:

fscanf(文件類型指針,格式字符串,輸入列表);

例如:

fscanf(fp, "%d", &i);
//作用是讀入fp所指向的文件中的i的值

例:將文件中的五個字符輸出。

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>

int main()
{
	FILE* fp;
	int i;
	char j;
	char filename[30];
	printf("請輸入文件名: ");
	scanf("%s", filename);
	if ((fp = fopen(filename, "r")) == NULL) /*判斷文件是否打開失敗*/
	{
		printf("無法打開文件!\n");
		system("pause");
		return 0;
	}
	for (i = 0; i < 5; ++i)
	{
		fscanf(fp, "%c", &j);
		printf("%d is: %c\n", i + 1, j);
	}
	fclose(fp);
	system("pause");
	return 0;
}

運行結果:
在這裏插入圖片描述
在這裏插入圖片描述

3.7 fread函數和fwrite函數
上邊介紹的fputc函數和fgetc函數每次只能讀寫文件中的一個字符,但是在編寫程序的過程中往往需要對整塊數據進行讀寫。fread和fwrite就可以實現此功能。

fread函數的一般形式如下:

fread(buffer, size, count, fp);

該函數的作用是從fp所指的文件中讀入count次,每次讀size字節,讀入的信息存在buffer地址中。

fwrite函數的一般形式如下:

fwrite(buffer, size, count, fp);

該函數的作用是將buffer地址開始的信息輸出count次,每次寫size字節到fp所指向的文件中。

例如:

fread(a,2,3,fp);
//從fp所指向的文件中每次讀入2個字節送入到數組a中,連續3次。
fwrite(a,2,3,fp);
//將a數組中的信息每次輸出2個字節到fp所指向的文件中,連續3次。

例:編程實現將錄入的通訊錄信息保存在磁盤文件中。在錄入完信息後,將所有錄入的信息全部顯示出來。

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>

struct address_list
{
	char name[10];
	char adr[20];
	char tel[15];
}info[100];

void save(char* name, int n)
{
	FILE* fp;
	int i;
	if ((fp = fopen(name, "wb")) == NULL) /*以只寫的方式打開*/
	{
		printf("文件打開失敗!\n");
		return ;
	}
	for (i = 0; i < n; ++i)
	{
		if (fwrite(&info[i], sizeof(struct address_list), 1, fp) != 1) /*將一組數據輸出到fp所指的文件中*/
		{
			printf("文件寫入失敗!\n");
		}
	}
	fclose(fp);
}

void show(char* name, int n)
{
	int i;
	FILE* fp;
	if ((fp = fopen(name, "rb")) == NULL) /*以只讀方式打開*/
	{
		printf("文件打開失敗!\n");
		return ;
	}
	for (i = 0; i < n; ++i)
	{
		fread(&info[i], sizeof(struct address_list), 1, fp); /*從fp所指向的文件讀入數據存放到數組中*/
		printf("%15s%20s%20s\n", info[i].name, info[i].adr, info[i].tel);
	}
	fclose(fp);
}

int main()
{
	int i = 0, n = 0;
	char filename[50];
	printf("請輸入學生人數: ");
	scanf("%d", &n);
	printf("請輸入文件名: ");
	scanf("%s", filename);
	printf("請輸入姓名、地址、電話號碼:\n");
	for (i = 0; i < n; ++i)
	{
		printf("No%d:", i + 1);
		scanf("%s%s%s", info[i].name, info[i].adr, info[i].tel);
		save(filename, n);
	}
	show(filename, n);
	system("pause");
	return 0;
}

在這裏插入圖片描述
在這裏插入圖片描述

4.文件的定位

在對文件進行操作時往往不需要從頭開始,只需要對其中指定的內容進行操作,這時就需要使用文件定位函數來實現對文件的隨機讀取。

4.1 fseek函數
其一般形式如下:

fseek(文件類型指針,位移量,起始點);

該函數的作用是移動文件內部位置指針。其中,“文件類型指針”指向被移動的文件;“位移量”表示移動的字節數,要求位移量是long型數據,以便在文件長度大於64KB時不會出錯。當用常量表示位移量時,要加後綴“L”;“起始點”表示從何處開始計算位移量,規定的起始點有文件首(SEEK_SET)、文件當前位置(SEEK_CUR)和文件尾(SEEK_END)。

例如:

fseek(fp, -20L, 1);
//表示將位置指針從當前位置向後退20個字節。
//fseek函數一般用於二進制文件。

例:向任意一個二進制文件中寫入一個長度大於6的字符串,然後從該字符串的第6個字符開始輸出餘下的字符。

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>

int main()
{
	FILE* fp;
	char filename[30], str[50];
	printf("請輸入文件名: ");
	scanf("%s", filename);
	if ((fp = fopen(filename, "wb")) == NULL) /*判斷文件是否打開失敗*/
	{
		printf("無法打開此文件!\n");
		return 0;
	}
	printf("請輸入字符串: ");
	getchar();
	gets(str);
	fputs(str, fp);
	fclose(fp);
	if ((fp = fopen(filename, "rb")) == NULL) /*判斷文件是否打開失敗*/
	{
		printf("無法打開!\n");
		return 0;
	}
	fseek(fp, 5L, SEEK_SET); /*將文件指針指向距文件首5個字節的位置,也就是指向字符串的第6個字符*/
	fgets(str, sizeof(str), fp);
	puts(str);
	system("pause");
	return 0;
}

運行結果:
在這裏插入圖片描述
在這裏插入圖片描述
4.2 rewind函數
rewind函數一般形式如下:

int rewind(文件類型指針);

該函數的作用是使指針重新返回文件的開頭,該函數無返回值。
例:rewind函數的使用。

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>

int main()
{
	FILE* fp;
	char ch, filename[50];
	printf("請輸入文件名:");
	scanf("%s", filename);
	if ((fp = fopen(filename, "r")) == NULL)
	{
		printf("無法打開這個文件!\n");
		return 0;
	}
	ch = fgetc(fp);
	while (ch != EOF)
	{
		putchar(ch);  /*輸出字符*/
		ch = fgetc(fp);  /*獲取fp指向文件中的字符*/
	}
	rewind(fp);  /*使文件內部指針指向文件的開頭*/
	ch = fgetc(fp);
	while (ch != EOF)
	{
		putchar(ch);  /*輸出字符*/
		ch = fgetc(fp);  /*獲取fp指向文件中的字符*/
	}
	fclose(fp);
	system("pause");
	return 0;
}

在這裏插入圖片描述
在這裏插入圖片描述
4.3 ftell函數
ftell函數的一般形式如下:

long ftell(文件類型指針);

該函數用於得到文件位置指針當前位置相對於文件首的偏移字節數。若返回-1L時,表示出錯。
例:求字符串長度。

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>

int main()
{
	FILE* fp;
	int n = 0;
	char ch, filename[30];
	printf("請輸入文件名: ");
	scanf("%s", filename);
	if ((fp = fopen(filename, "r")) == NULL)
	{
		printf("文件打開失敗!\n");
		return 0;
	}
	ch = fgetc(fp);
	while (ch != EOF)
	{
		putchar(ch);  /*輸出字符*/
		ch = fgetc(fp);/*再次獲取fp所指向的文件中的字符*/
	}
	n = ftell(fp);
	printf("\n該文件中的字符串長度爲: %d\n", n);
	system("pause");
	return 0;
}

運行結果:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章