C语言 文件操作

前言:只有接触了文件的代码,才算真正的编程,那么,这篇博客就来简单介绍一下文件吧
文件的定义:
文件是一个外存的范畴;文件是计算机表达信息的最小逻辑单位;文件就是信息二进制化后在外存中的存储。

文件的组成

  1. 文件名;
  2. 文件的主体内容;
  3. 文件属性。

文件内容
所有的内容都是二进制的!
在这里要提到一点:操作系统(OS)在管理文件时,使用“文件控制块(FCB)”这样的数据。
(所谓“文件控制块”,实质上是关于一个文件的一堆数据,数据越详细,OS对于文件的掌控越详尽)而且,FCB是OS的有限资源。
不同的程序设计语言,都对于文件的操作给出了;
不同的程序设计语言对于FCB进行了各自的表示和封装(C语言用FILE来封装FCB)

对文件进行编程,需要先申请FCB。

现在,就来介绍一下有关文件处理基本的几个函数吧:
首先,要声明一点,所有相关函数都包含在<stdio.h>头文件中

1.FILE *fopen(“文件名”,“打开方式”):
这里的打开方式,有以下几种:
在这里插入图片描述fopen()的本质申请操作系统的FCB资源

2.int fclose(FILE *文件指针):
相对地,fclose的本质相当于归还FCB资源
关于返回值:
如果成功关闭,则该方法返回0
如果失败,则返回 EOF

3.int fprintf(FILE *文件指针,“格式符”,...):
功能:向文件指针所指向的文件中写入相应类型的数据。
(写入数据时,本质上是字符串)
关于返回值:
如果成功,则返回写入的字符总数
如果失败返回一个负数
注意:fprintf(stdout,"格式符",...)等价于printf("格式符",...)

4.int fscanf(FILE *文件指针,“格式符”,...):
从文件指针所指向的文件中读取数值并赋值给相应变量。
(读取数据时,首先是字符串,然后根据格式符转换为相应格式)
关于返回值:
如果成功,该函数返回成功匹配和赋值的个数
如果到达文件末尾发生读错误,则返回 EOF
注意:fscanf(stdin,"格式符",...)等价于scanff("格式符",...)

5. char* fgets(char *目标字符串(str), int 最大字符数, FILE *文件指针):
功能:从文件指针所指文件中读取一行,并把它存储在 str 所指向的字符串内。
当读取 (n-1) 个字符时,或者读取到换行符时,或者到达文件末尾时,它会停止,具体视情况而定。
关于返回值:
如果成功,该函数返回相同的 目标字符串
如果到达文件末尾或者没有读取到任何字符str 的内容保持不变,并返回一个空指针
如果发生错误返回一个空指针

6.int fputs(const char *s, FILE *文件指针)
(说明:s -- 这是一个字符串,包含了要写入的以空字符终止的字符序列)
功能:把字符串写入到文件指针所指向的文件中,但不包括空字符。
关于返回值:
成功返回一个非负值
如果发生错误返回 EOF

7.int fgetc(FILE *文件指针):
功能:从文件指针所指向的文件中读取一字节的信息
关于返回值:
该函数以无符号 char 强制转换为 int 的形式返回读取的字符
如果到达文件末尾发生读错误,则返回 EOF

8.int putc(int 要被写入的字符, FILE * 文件指针):
功能:将目标字符写入文件指针所指向的文件中。
关于返回值:
如果成功,则返回被写入的字符
如果发生错误,则返回 EOF,并设置错误标识符

9.int feof(FILE *文件指针):
功能:对上一次(紧上一次)的文件操作是否正确判定。
关于返回值:
成功返回值为0
失败,则为返回值非0

10.size_t fwrite(const void *被写入元素数组的指针, size_t 被写入的每个元素的大小, size_t 元素个数, FILE *文件指针):
说明:被写入元素的大小按照二进制为单位
功能:将数组,结构体等类型的值写入指定文件中
关于返回值:
如果成功,该函数返回一个 size_t 对象,表示元素的总数,该对象是一个整型数据类型
如果该数字与 元素个数 参数不同,则会显示一个错误

11.size_t fread(void *要存入元素的数组的指针, size_t 要读取每个元素大小, size_t 元素个数, FILE *文件指针):
说明:被写入元素的大小按照二进制为单位
功能:从数组,结构体中读取指定大小数据
关于返回值:
成功读取的元素总数会以 size_t 对象返回size_t 对象是一个整型数据类型
如果总数与 nmemb 参数不同,则可能发生了一个错误或者到达了文件末尾

12.long int ftell(FILE *文件指针):
功能:用于查看文件大小或指针对于初始位置的相对偏移量
说明,正常使用的返回值为当前位置距离初始位置的偏移量,单位为字节。
关于返回值:
如果使用成功该函数返回位置标识符的当前值
如果发生错误,则返回 -1L,全局变量 errno 被设置为一个正值

13.int fseek(FILE *stream, long int 偏移量, int 常量):
功能:将文件指针指向目标位置;
说明:关于常量,一共有三种情况:
在这里插入图片描述
关于返回值:
如果成功,则该函数返回零
否则,返回非零值

14.int rename(const char *原文件名, const char *新文件名):
功能:顾名思义,给文件改名的函数。

15.int remove(const char *要删除的文件名):
功能;删除指定名的文件。

那么以上就是我们对于文件操作的基本函数了。

现在,我们就来实现一些常用的文件操作吧!
首先,假设已有文件为data.txt
那么,文件的内容展示(showFile.c):

#include <stdio.h>

int main() {
	FILE *fp;
	int ch;

	fp = fopen("data.txt", "r");

	ch = fgetc(fp);
	while (!feof(fp)) {
		printf("%c", ch);
		ch = fgetc(fp);
	}
	printf("\n!!!\n");

	fclose(fp);

	return 0;
}

文件内容复制(copyFile.c):
(假设将data.txt的内容复制给data.sav)

#include <stdio.h>

int main() {
	FILE *fpIn;
	FILE *fpOut;
	int ch;

	fpIn = fopen("data.txt", "r");
	fpOut = fopen("data.sav", "w");

	ch = fgetc(fpIn);
	while (!feof(fpIn)) {
		fputc(ch, fpOut);
		ch = fgetc(fpIn);
	}

	fclose(fpIn);
	fclose(fpOut);

	return 0;
}

将 数组 写入指定文件中(aboutBinary.c):

#include <stdio.h>

int main() {
	FILE *fp;
	int arr[10] = {1, 100, 1000, 10000, 100000};	
	// {0x00000001, 0x00000064, 0x000003E8, 0x00002710, 0x000186A0}
	int i;

	fp = fopen("abcd.dat", "wb");
	fwrite(arr, sizeof(int), 5, fp);
	//等同于 for (i = 0; i < 5; i++) {
	// 	          fwrite(arr + i, sizeof(int), 1, fp);
	//            }

	fclose(fp);

	return 0;
}

将 结构体 写入指定文件中(aboutStruct.c):

#include <stdio.h>

typedef struct {
	int one;
	char two;
	int three;
	double four;
}MY_TYPE;

int main() {
	MY_TYPE num = {
		0x12,
		'A', // 0x41
		0x135,
		3.14,
	};
	FILE *fp;

	fp = fopen("abcde.dat", "wb");        //wb是用二进制方式写入的打开方式
	fwrite(&num, sizeof(MY_TYPE), 1, fp);

	fclose(fp);

	return 0;
}

在之前的一篇博客《(带头节点的链表) 宿舍管理系统)》中,我们提到了文件,那么,现在我们用文件来简单实现一下基本的操作吧:
首先,录入信息函数:

boolean enterInf(NEW_TYPE *ptr, int size, int count, FILE *fp){
	if(NULL == fp) {
		return FALSE;
	}
	fwrite(ptr, size, count, fp);
	return TRUE;
}

这里对上面这段这段代码做几点说明:
1.这个函数存在前提是文件以“wb”形式打开了(有打开就一定要记得关闭);
2.关于参数size,可以在引用函数时写作sizeof(NEW_TYPE);
3.关于返回值,可以在主函数中用来判断用户是否使用错误

其次,是查看信息函数:
要制作查看函数,我们根据之前制作管理系统的知识,将函数做成查找指定信息和查看单独信息的两个函数
1.查找单独信息:

boolean seekOne(FILE *fp, int count, size_t NEW_TYPE) {
	int no;
    if(NULL == fp) {
		return FALSE;
	}
	printf("请输入要查看信息编号: ");
	scanf("%d", &no);
	if(no > count) {
		return FALSE;
	}
	fseek(fp, sizeof(NEW_TYPE) * no, SEEK_SET);
	return TRUE;
}

2.显示一个信息:

void showOne(FILE *fp, size_t NEW_TYPE) {
	char NEW_TYPE[sizeof(NEW_TYPE)];
	if(NULL == fp) {
		return FALSE;
	}
	fread(NEW_TYPE, sizeof(NEW_TYPE), 1, fp);
	printf("%s", NEW_TYPE);
}

3.显示指定信息:

void showInf(FILE *fp, size_t NEW_TYPE) {
	if(NULL == fp) {
		return FALSE;
	}
	seekOne(fp, sizeof(ftell(fp))/sizeof(NEW_TYPE), size_t NEW_TYPE);
	showOne(fp);
}

4.显示信息表:

void showAllInf(FILE *fp, size_t NEW_TYPE) {
	printf("表头");
	for(i=0, i<count, i++) {	//这里的count变量是我们存储的信息的数量,我们可以通过一个全局变量实现
		fseek(fp, sizeof(NEW_TYPE) , SEEK_CUR);
		showOne(fp);
	}
}

再者,增添信息函数:

boolean addInf(FILE *fp, size_t NEW_TYPE) {
	int no;
	printf("请输入要插入信息编号:");
	scanf("%d", no);
	if(NULL == fp) {
		return FALSE;
	}
	seekOne(fp, sizeof(ftell(fp))/sizeof(NEW_TYPE), size_t NEW_TYPE);
	fwrite(&num, sizeof(MY_TYPE), 1, fp);
}
posted @ 2020-03-04 17:51  在下右转,有何贵干  阅读(281)  评论(0编辑  收藏  举报