前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【C语言】文件操作

【C语言】文件操作

作者头像
举杯邀明月
发布于 2023-04-12 09:22:17
发布于 2023-04-12 09:22:17
4K00
代码可运行
举报
文章被收录于专栏:C++&linuxC++&linux
运行总次数:0
代码可运行

本文介绍了C语言中关于文件操作的内容知识,内容较为生涩,没有理解可以多次观看



一、为什么使用文件

我们在写代码的过程中,有的时候某一些数据我们是想把它保存下来的,而不是说只有在程序运行的时候,这些数据才能被我们录入或显示出来,我们总会遇到数据持久化的场景,所以这时我们需要将数据保存下来,一般数据持久化的方式有,把数据存到磁盘文件里,或存放到数据库里面

以后我们如果想导出这部分的数据时,只要打开磁盘的文件就行了,就可将数据导入到我们所期望的程序当中

二、 数据、程序、文件

2.1 数据

数据是事实或观察的结果,是对客观事物的逻辑归纳,是用于表示客观事物的未经加工的原始素材。数据可以是连续的值,比如声音、图像、温度、压力等都称为模拟数据,也称为模拟量,相对于数字量而言,指的是取值范围是连续的变量或者数据。模拟数据是指在某个区间产生的连续值。当然数据也可以是离散的,如符号、文字称为数字数据

在计算机系统中,数据以二进制信息单元0、1 的形式表示

在计算机科学中,数据是指所有能输入计算机并被计算机程序处理的符号的介质的总称,是用于输入电子计算机进行处理,具有一定意义的数字、字母、符号和模拟量等的通称。计算机存储和处理的对象十分广泛,表示 这些对象的数据也随之变得越来越复杂。

对于逻辑归纳,比如电路,开和关分别对应着二进制数字1和0,对于一个电路,这是一个事实,而对于电路中开路断路的描述,则是通过数据来实现的。这就是逻辑归纳的数据

2.2 程序

计算机程序是一组计算机能识别和执行的指令(说的简单点就是代码呗,我们平常敲的计算机能读懂的东西),这种指令运行于电子计算机上,也是满足人们需求的一种信息化工具。

他以某些程序设计语言编写,运行于某种目标结构体系上。

举个栗子,程序就如同以英语(程序设计语言)写作的文章,要让一个懂得英语的人(编译器)同时也会阅读这篇文章的人(结构体系)来阅读、理解、标记这篇文章。一般的,以英语文本为基础的计算机程序要经过编译、链接而成为人难以解读,但可轻易被计算机所解读的数字格式,然后放入计算机内部运行。

2.3 数据和程序的关系

数据得到程序指令的处理,才能得到大多数普通人能看懂的数据(网页,app,游戏),数据只有得到程序的处理才有价值,也只有处理之后才能被称为是信息,单纯的数据其实是没有任何的意义的

2.4文件

计算机文件(或称文件、电脑档案、档案),是存储在某种长期储存设备上的一段数据流。所谓“长期储存设备”一般指磁盘、光盘、磁带等。其特点是所存信息可以长期、多次使用,不会因为断电而消失。计算机文件分为文本文件和二进制文件,文本文件仅由字符的串行构成,除此之外的文件都是二进制文件。

2.4程序设计中所谈文件

在程序设计中,我们所谈的文件,一般有两种,程序文件和数据文件(根据文件功能所划分)

2.4.1程序文件

包括源程序文件(后缀为.c),目标文件(windows环境下后缀为.obj),可执行程序(windows环境下是.exe)

2.4.2数据文件

文件的内容不是程序指令,而是程序运行时读入和写入的数据,可能包括程序运行需要从中读取数据的文件或输出内容的文件

我们着重讨论数据文件 我们最常见到的就是将数据从标准输入流(键盘)输入,显示到标准输出流(屏幕、也就是显示器)中 其实有时候我们会将数据输出到磁盘文件上,当需要的时候,再将数据从磁盘文件中拿出来,这时我们就必须学会在程序中如何操作文件

三、文件的打开和关闭(包含如何对一个文件进行读写)

3.1文件指针

讲解文件指针之前,我们先来给大家介绍一下,缓冲文件系统

ANSI C标准采用“缓冲文件系统”处理数据文件。 所谓缓冲文件系统是指系统自动地在内存区为程序中每一个正在使用的文件开辟一个文件缓冲区。 如果从内存向磁盘输出数据必须先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘中的文件里面去。 如果从磁盘向计算机读入数据,则一次从磁盘文件将一批数据输入到内存缓冲区 (充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区 (给程序变量) 。

举个栗子: 我们在程序中使用到的文件都会开辟一个文件信息区(存放文件信息),这些存在于系统声明的信息都是由编译器的开发人员(微软员工)定义好类型的,并且该结构体的类型声明为FILE(源码中利用FILE创建了一个_public_file变量)。

每当我们打开一个文件时,系统会根据文件的情况自动创建一个FILE类型的结构体变量,用于填充我们文件情况的信息,我们在使用时,直接使用就好了,不必关心操作系统是如何操作的

所以我们就可以定义一个文件指针变量

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
FILE*pf;      这个变量可以存放我们打开的磁盘中文件的地址

然后我们就可以通过这个指针,去访问,它所维护的那个文件中所存储的信息了

3.2文件的打开和关闭(对文件进行读写)

文件在读写之前应该先打开文件,在我们使用完毕之后要关闭文件

ANSI C规定使用fopen和fclose函数来打开和关闭文件,下面是fopen和函数fclose的介绍

我们打开文件的方式,C语言规定有以下几种:

从介绍中可以读出,fopen是需要两个参数的第一个是我们的文件名,第二个参数是我们打开文件的方式,我们如果只读或只写或追加的话,打开文件的方式由表格可知,有三种,分别是(“r”,“w”,“a”)。而且他的返回值也是一个指向打开这个文件的指针,如果打开失败,他会返回一个空指针,所以在接收fopen函数返回值时,我们一般还要判断返回值是否有效,也就是确定他是否为空指针

3.3如何利用库函数来读写文件

举个栗子: 我们先来介绍几个有关写入数据到文件里面的函数

3.3.1 fgetc和fputc

fgetc,fputc分别是字符输入函数和字符输出函数,他们都适用于所有输入流和所有输出流,如果你记不住这几个函数的功能分别是什么,其实将他翻译一下就好了,get character of file和put character of file其实就是从流中读取出一个字符和向流中写入一个字符的功能

int fgetc( FILE *stream );参数是文件指针,也就是你要操作的文件地址 int fputc( int c, FILE *stream );第一个参数是你要写进去的字符(它以ascll码值的形式存储),第二个参数是文件指针,也就是你要操作的文件地址

1.fputc代码展示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int main()
{
	FILE* pfwrite = fopen("test.txt", "w");//以只写的方式打开文件名为test.txt的文件,路径在我们这个工程的目录底下
	if (pfwrite == NULL)
	{
		printf("%s", strerror(errno));
		return 0;
	}
	//写文件,用fputc将字符写到文件流中
	else
	{
		fputc('l', pfwrite);
		fputc('o', pfwrite);
		fputc('v', pfwrite);
		fputc('e', pfwrite);
	}
	//关闭文件,将指针置为空指针
	fclose(pfwrite);
	pfwrite == NULL;

	return 0;
}

2.fgetc代码展示

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int main()
{
	FILE* pfread = fopen("test.txt", "r");
	if (pfread == NULL)
	{
		printf("%s", strerror(errno));
	}
	else
	{
		printf("%c", fgetc(pfread));
		printf("%c", fgetc(pfread));
		printf("%c", fgetc(pfread));
		printf("%c", fgetc(pfread));
	}
	//关闭文件,将文件指针置为空指针
	fclose(pfread);
	pfread == NULL;

	return 0;
}

3.3.2 fgets和fputs

fgets,fputs分别是文本行输入函数和文本行输出函数,他们都适用于所有输入流和所有输出流,get string of file和put string of file,其实就是从一个流中读取字符串和向一个流中写入字符串

int fputs( const char *string, FILE *stream );第一个参数是你要放到文件里面的字符串,第二个参数是你所操作的文件指针 char *fgets( char *string, int n, FILE *stream );第一个参数是你从文件读取出来字符串后,字符串所存储的地方(可以是一个字符数组),第二个参数是你所读取的字符串的最大字符个数,第三个参数是你所操作的文件地址,也就是文件指针

1.fputs代码展示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int main()
{
	FILE* pf = fopen("test.txt", "w");
	char buf[1024] = { 0 };
	if (pf == NULL)
	{
		printf("%s", strerror(errno));
		return 0;
	}
	else
	{
		fputs("wyn", pf);
		//fgets(buf, 1024, pf);
		//printf("%s", buf);
	}
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

2.fgets代码展示

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int main()
{
	FILE* pf = fopen("test.txt", "r");
	char buf[1024] = { 0 };
	if (pf == NULL)
	{
		printf("%s", strerror(errno));
		return 0;
	}
	else
	{
		//fputs("wyn", pf);
		fgets(buf, 1024, pf);
		printf("%s", buf);
	}
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

3.3.3 fscanf和fprintf

fscanf,fprintf分别是格式化输入函数和格式化输出函数,他们也适用于所有输入流和所有输出流,我们对scanf和printf是比较熟悉的,我们知道他是一种格式化的输入和输出函数,但我们以前都知道,使用scanf或printf时我们只需要向其中输入数据让printf在显示器里显示出来就可以了,但其实这两个函数只是使用了默认输入流(键盘)和输出流设备(屏幕显示器),scanf: Read formatted data from the standard input stream. printf: Print formatted output to the standard output stream.

而我们现在介绍的这两个函数其实多了一个参数,这个参数就是指向文件的文件指针,我们可以更改这个文件流。

int fprintf( FILE *stream, const char *format [, argument ]…); int printf( const char *format [, argument]… );

通过函数互相的对比,我们可以轻松看出fprintf和fscanf的第二个参数其实就是格式化的形式,我们可以自己去定义这个格式

int fscanf( FILE *stream, const char *format [, argument ]… ); int scanf( const char *format [,argument]… );

1.fprintf代码展示

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
typedef struct stu
{
	int n;
	float score;
	char arr[10];
}stu;
int main()
{
	stu s1 = { 100,3.14f,"iloveyou" };
	FILE* pf = fopen("test.txt", "w");
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 0;
	}
	fprintf(pf, "%d %f %s", s1.n, s1.score, s1.arr);
	//我们将信息内容打印到文件流pf里面去
	fclose(pf);
	pf = NULL;
	return 0;
}

原来的printf是把信息打印到标准输出流里面,但现在我们可以通过fprintf将信息打印到文件输出流里面,其实说白了就是,改变了信息的目的地,原来的目的地是显示器,现在的目的地可以是文件

2.fscanf代码展示

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
typedef struct st
{
	int n;
	float score;
	char arr[10];
}stu;
int main()
{
	stu s1 = { 0 };
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 0;
	}
	fscanf(pf, "%d %f %s", &(s1.n), &(s1.score), s1.arr);
	//从文件中将信息输入到我们想要存放的变量里面去,以前是从键盘中将信息输入到变量里面去	
	fprintf(stdout, "%d %f %s", s1.n, s1.score, s1.arr);
	//从标准输出流(屏幕)中将我们存放到变量中的信息打印出来

	fclose(pf);
	pf = NULL;
	return 0;
}

原来的scanf是,把我们从标准输入流设备(键盘),输入的信息存放到我们创建的变量里面去,但现在的fscanf是从文件流里面将我们的信息存放到我们所创建的变量,其实说白了就是改变了信息的来源方式,原先来自于键盘,现在可以来自于文件

3.3.4 fread和fwrite

fread,fwrite分别是二进制输入函数和二进制输出函数,他们的适用范围只有文件流这一种流,是不包括标准输入和输出流的(这个需要特殊记忆一下)

size_t fread( void *buffer, size_t size, size_t count, FILE *stream );第一个参数是我们从文件中读取数据后,数据要被暂时存放的位置,第二个参数是我们读取的信息的字节大小,第三个参数是要读取的项目整体大小,第四个参数是从哪个文件里读取,我们需要传一个文件的地址 size_t fwrite( const void *buffer, size_t size, size_t count, FILE *stream );fwrite函数和fread函数只有第一个参数是不一样的,我们这里只给介绍第一个参数,第一个参数是我们要将变量中存放的信息写到文件里面去,我们传过去的是变量的地址

1.fwrite代码展示

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
typedef struct stu
{
	char name[20];
	int age;
	double score;
}stu;
int main()
{
	stu s = { "张三",20,55.9 };
	FILE* pf = fopen("test.txt", "wb");
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 0;
	}
	fwrite(&s, sizeof(stu), 1, pf);
	
	fclose(pf);
	pf = NULL;
	return 0;
}

注意这里的文件内容是二进制形式的,并不是文本内容,所以我们是看不懂的,如果想看懂特德内容,可以用fread函数将文件中的信息以二进制的形式读取出来方便我们查看

2.fread代码展示

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
typedef struct stu
{
	char name[20];
	int age;
	double score;
}stu;//注意stu现在是一种类型
int main()
{
	stu s = { "张三",20,55.9 };
	stu tmp = { 0 };
	FILE* pf = fopen("test.txt", "rb");
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 0;
	}
	fread(&tmp, sizeof(stu), 1, pf);
	printf("%s %d %lf", tmp.name, tmp.age, tmp.score);
	fclose(pf);
	pf = NULL;
	return 0;
}

这里通过运行结果可以看出,我们上面的fwrite函数成功将信息以二进制的形式写到文件test.txt里面去了,正因为如此,我们通过二进制读取的方式才能将文件的信息以我们能看懂的方式输出到屏幕上

3.4 对比一组函数的功能(加深对输入输出函数的理解)

1.scanf/printf 是针对标准输入流/标准输出流的 一种格式化输入语句和输出语句 2.fscanf/fpirntf 是针对所有输入流/所有输出流的 一种格式化输入语句和输出语句(包含文件输入流和文件输出流) 3.sscanf/sprintf 是从字符串中读取格式化的数据 是把格式化的数据存储到(输出成)字符串

这里我们看一下,sscanf和sprintf这两个函数的声明介绍

int sscanf(const char* buffer, const char* format[, argument] …); int sprintf(char* buffer, const char* format[, argument] …);

通过观察我们可以看到,其实这两个函数与最初的scanf和printf相比,只是多了一个要传缓冲区地址的这么一个参数

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
typedef struct stu
{
	int n;
	float score;
	char arr[10];
}stu;
int main()
{
	stu s = { 1024,3.14,"love" };
	stu tmp = { 0 };
	char buf[1024] = { 0 };
	 
	sprintf(buf, "%d %f %s", s.n, s.score, s.arr);
	//原来是输出到屏幕上,现在我们将一组格式化的数据输出到(存储到)字符串数组buf里面
	printf("%s\n", buf);
	//将格式化的数据转换成字符串存储到buf里面,我们在打印到stdout中

	sscanf(buf, "%d %f %s", &(tmp.n), &(tmp.score), tmp.arr);
	//原来是从键盘这种标准输入流中将信息输入到我们想要放到的变量 里面
	//现在我们从buf这种输入流,将信息输入到我们想要的变量(结构体tmp)里面
	printf("%d %f %s\n", tmp.n, tmp.score, tmp.arr);
	return 0;
}

通过代码运行结果可以看出,我们成功将一组格式化的数据写到字符数组里面,也成功的将字符串数组里面的内容拿出来,存放到我们想让他存在的变量里面,其实就是将原来的scanf和printf的功能扩大了一个使用的范围

四、文本文件和二进制文件

根据数据的组织形式,我们将数据文件分为文本文件和二进制文件

数据在内存中以二进制的形式存储,如果不加转换的输出到外存,那就是二进制文件,如果我们将数据的形式转换为ascll码的话,那就是文本文件

值得注意的是,字符在内存中均以ascll码的形式存储,数值型数据既可以用ascll形式存储,也可以用二进制形式存储

当用ascll形式存储时,我们会将10000看成5个字符,我们将这5个字符所对应的ascll码值,存储到内存里面 当用二进制形式存储时,10000其实就是个整型,我们将它按照4字节32比特位存储即可

五、文件的随机读写

前面给大家介绍的fgetc,fputc,fgets,fputs,fscanf,fprintf,fread,fwrite等操作文件的函数,其返回的指针是有统一顺序的,他的文件指针都是指向文件内容的第一个信息数据的地址的。

这里我们给大家介绍一下,能够改变文件指针指向位置的三个函数

5.1 fseek

函数具体功能实现:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int main()
{
	FILE* pf = fopen("test.txt", "r");//以只读的方式打开文件test.txt
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
	}

	//1.定位文件指针
	fseek(pf, -2, SEEK_END); 
	
    //2.读取文件
	int ch = fgetc(pf);//从pf指向的文件中读取内容
	printf("%c", ch);

	//3.关闭文件 
	fclose(pf);
	pf = NULL;
	return 0;
}

这里的fseek可以调整指针位置,以当前位置为起点,移动特定的偏移量到我们想要的位置

5.2 ftell

函数具体功能实现:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int main()
{
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
	}
	int ch = fgetc(pf);//从pf指向的文件中读取第一个字符,相应的指针位置相对于起始量偏移了1
	int h = fgetc(pf);//偏移了2
	int pos = ftell(pf);//所以这里的ftell返回值应该是2
	printf("%d\n", pos);//结果应为2
	return 0;
}

我们这里的ftell函数作用起始就是返回当前文件指针相对于起始位置的偏移量

5.3 rewind

函数功能实现:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int main()
{
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
	}
	int ch = fgetc(pf);
	int h = fgetc(pf);
	int pos = ftell(pf);
	printf("%d\n", pos);//结果为2

	rewind(pf);//我们这里让文件位置重新回到起始位置
	pos = ftell(pf);//然后再用ftell返回当前文件指针的偏移量大小
	printf("%d\n", pos);//返回到起始位置后,结果为0

	return 0;
}

所以这个函数功能也是比较简单的,就是重置我们的文件指针指向的位置,让他回到起始位置

六、文件读取结束的判定

6.1 feof的错误使用

Tests for end-of-file on a stream.这个是feof的函数介绍,我们可以知道,这个函数是用来测试文件结束形式的。所以这个函数不是用来判断文件是否结束的,而是用来判定文件是如何结束的,到底是因为读取到\0结束的?还是因为其他原因导致文件读取错误,而导致文件结束的?

所以很多人看到feof(end of file)时会把他认为成一个判断文件是否结束的函数,但其实不是这样的The feof function returns a nonzero value after the first read operation that attempts to read past the end of the file. It returns 0 if the current position is not end of file. There is no error return.通过这里的feof函数的返回值介绍(如果当前位置不是文件末尾则返回一个0(有可能发生了读取文件错误),如果成功读取结束的话,将返回一个非0值),我们就可以明白了,这个函数的确是用来测试文件读取结束的方式的,既有可能是读取错误导致的结束,也有可能是读到文件末尾,从而导致的读取结束

6.2 ferror、perror、strerror的对比

perror ( )用 来 将 上 一 个 函 数 发 生 错 误 的 原 因 输 出 到 标 准 错误 (stderr) 。参数 s 所指的字符串会先打印出,后面再加上错误原因字符串。此错误原因依照全局变量errno 的值来决定要输出的字符串。 在库函数中有个error变量,每个error值对应着以字符串表示的错误类型。当你调用"某些"函数出错时,该函数已经重新设置了error的值。perror函数只是将你输入的一些信息和现在的error所对应的错误一起输出。

1.ferror(fault error)的功能: 测试流上的错误。如果流上没有发生错误,ferror返回0。否则,它返回一个非零值。 2.perror的功能: 直接打印错误信息(里面包含我们所输入的信息和错误码所对应的信息一并打印出来) 3.strerror的功能: 把错误码对应的错误信息的字符串地址返回(配合errno使用,errno是一个全局变量,当出现错误时,errno会对应一个库中错误信息对应的错误码,然后我们再用strerror打印这个错误码对应的错误信息)

6.3 判断文件结束的两个例子

6.3.1 文本文件的判断

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
文本文件的例子:
int main(void)
{
	int c; // 注意:int,非char,要求处理EOF
	FILE* fp = fopen("test.txt", "r");
	if (!fp) //fp是空指针的时候,进入到if语句,输出错误信息
    {
		perror("File opening failed");
		return  ;
	}
	//fgetc 当读取失败的时候或者遇到文件结束的时候,都会返回EOF
	while ((c = fgetc(fp)) != EOF) // 标准C I/O读取文件循环
	{
        //这里循环的条件就是,读取的字符不是EOF,一直将字符输出
		putchar(c);
	}
    //文件读取之后结束了,然后判断是什么原因结束的
	if (ferror(fp))//发生错误,返回一个非0值,进入if语句,打印读取失败的信息
		puts("I/O error when reading");
    //在读取文件时,input或output发生错误
	else if (feof(fp))
    //如果函数feof返回非0值,说明是遇到了EOF结束的,如果当前的位置不是文件末尾,则返回0,也就不是遇到EOF
		puts("End of file reached successfully");
	fclose(fp);
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
自己实现相应的代码,加深理解
int main()
{
    FILE* pf = fopen("test.txt", "r");
    if (pf == NULL)
    {
        return 0;
    }
    //读文件
    int ch = 0;
    while ((ch = fgetc(pf)) != EOF)
    {
        putchar(ch);
    }
    printf("\n");
    //跳出循环,判断是怎么结束的???
    if (ferror(pf))//是读取失败结束???
    {
        printf("error\n");
    }
    else if (feof(pf))//还是遇到文件尾结束???
    {
        printf("end of file\n");
    }
    
    fclose(pf);
    pf = NULL;
    return 0;
}
总结:所以ferror和feof要配合使用,以此来判断是读取失败结束还是遇到文件尾结束
ferror如果检测没有错误返回0 有错误返回非0值
feof如果没到文件尾的话他会返回一个0,到达文件尾返回一个非0

6.3.2二进制文件的判断

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//二进制文件例子:
#include <stdio.h>
enum 
{
    SIZE = 5 
};
int main(void)
{
    double a[SIZE] = { 1.,2.,3.,4.,5. };
    FILE* fp = fopen("test.bin", "wb"); // 必须用二进制只读模式
    fwrite(a, sizeof * a, SIZE, fp); // 写 double 的数组到pf流里面去
    fclose(fp);//然后关闭文件

    double b[SIZE];
    fp = fopen("test.bin", "rb");
    size_t ret_code = fread(b, sizeof * b, SIZE, fp); //  将从fp流中读取的数据放到double数组b里面(以二进制的形式读出来)
    if (ret_code == SIZE)
    //如果返回值等于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))
 //(到达文件尾返回一个非0值进入if语句,但它并非我是所预取的文件结束位置,虽然我的预期有可能是错误的,但你返回值<SIZE,我认为这就是unexpected的)
        {
            printf("Error reading test.bin: unexpected end of file\n");
            //提前阅读文件结束,导致返回值小于SIZE,这时unexpected end of file非预期文件结束
        }
        else if (ferror(fp)) 
        {
            perror("Error reading test.bin");//读取错误导致文件读取结束
        }
    }
    fclose(fp);
}

6.4文本文件和二进制文件的对比

(1)文本文件读取是否结束,判断返回值是否为EOF(fgetc),或者NULL(fgets) 例如: fgetc判断是否为EOF(fgetc返回读取为int的字符,或返回EOF以指示错误或文件结束)

fgets判断是否为NULL(返回NULL表示错误或文件结束条件,使用feof或ferror来确定是否发生了错误)

(2)二进制文件的读取结束判断,判断返回值是否小于实际要读的个数 例如:fread判断返回值是否小于实际要读的个数 (Fread返回实际读取的完整项数,如果发生错误或在达到count之前遇到文件结束,则该数可能小于count)

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-01-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
堪称一站式管理平台,同时支持Linux、MySQL、Redis、MongoDB可视化管理!
mayfly-go号称Web版Linux、数据库、Redis、MongoDB统一管理操作平台,是一款开源的可视化管理工具。
macrozheng
2022/12/14
1K0
堪称一站式管理平台,同时支持Linux、MySQL、Redis、MongoDB可视化管理!
Star 1.6k!当Web遇上Linux和数据库!一站式管理平台的开源之旅!
在现代软件开发和运维中,管理和操作各种不同类型的服务器和数据库是一个复杂而又重要的任务。虽然有一些现成使用到的服务器管理工具和数据库管理应用,比如:XShell、Termius、Navicat等。但是它们都是分开使用的。
Python兴趣圈
2024/01/12
6480
Star 1.6k!当Web遇上Linux和数据库!一站式管理平台的开源之旅!
推荐一款一站式Linux&数据库管理平台《mayfly-go》
平时工作过程中,对于远程连接Linux,我们通常会使用SSH工具如:putty、xshell等,对于mysql、mongodb数据库管理通常会使用Navicat、Dbeaver这类工具,redis则有RedisDesktopManager,部分软件可能还需要破解才能使用。每次都要安装来安装去、安装多个软件,这样不免有些繁琐。那么有没有一款工具可以提供一站式管理呢,答案是有的。mayfly-go就是最近比较火的,一款开源的web版linux、mysql、redis、mongo统一管理操作平台。
大刚测试开发实战
2022/11/14
2.2K0
推荐一款一站式Linux&数据库管理平台《mayfly-go》
【每日精选时刻】前端如何优雅的设计字典值?如何使用DSL解决问题?裸机也能启动C++?
大家吼,我是你们的朋友煎饼狗子——喜欢在社区发掘有趣的作品和作者。【每日精选时刻】是我为大家精心打造的栏目,在这里,你可以看到煎饼为你携回的来自社区各领域的新鲜出彩作品。点此一键订阅【每日精选时刻】专栏,吃瓜新鲜作品不迷路! *当然,你也可以在本篇文章,评论区自荐/推荐他人优秀作品(标题+链接+推荐理由),增加文章入选的概率哟~
社区好文捕手-煎饼狗子
2024/04/10
2160
这款 Linux、数据库、Redis、MongoDB 统一管理平台,有点牛逼!
基于DDD分层实现的web版 linux(终端 文件 脚本 进程)、数据库(mysql postgres)、redis(单机 集群)、mongo统一管理操作平台
民工哥
2022/10/27
9440
这款 Linux、数据库、Redis、MongoDB 统一管理平台,有点牛逼!
【自动化测试】一站式测试平台MeterSphere实践感悟分享
本篇仅做个人的一些实践感悟分享,不会涉及具体功能的使用,详细的可查看其它小伙伴的分享,MeterSphere金融公司落地经验分享。
用户9913368
2022/08/13
1K0
一站式元数据治理平台——Datahub入门宝典
随着数字化转型的工作推进,数据治理的工作已经被越来越多的公司提上了日程。作为新一代的元数据管理平台,Datahub在近一年的时间里发展迅猛,大有取代老牌元数据管理工具Atlas之势。国内Datahub的资料非常少,大部分公司想使用Datahub作为自己的元数据管理平台,但可参考的资料太少。
用户6070864
2022/01/04
7K2
一站式元数据治理平台——Datahub入门宝典
推荐一款Linux、MySQL、Redis、MongoDB统一管理平台,太牛了!
程序员在工作中避免不了要操作 myql、redis、Linux 等。所以要安装很多工具,Navicat、Xshell、RedisDesktopManager等,今天给大家推荐一款工具,可以代替这些常规工具,统一管理监控这些资源信息。
永恒君
2022/12/07
1.6K0
推荐一款Linux、MySQL、Redis、MongoDB统一管理平台,太牛了!
解密服务性能利器:Pyroscope让你的应用飞起来
开发人员通常需要查看生产应用程序中的性能瓶颈以确定问题的原因。为此,您通常需要可以通过日志和代码工具收集的信息。不幸的是,这种方法通常耗时,并且不能提供有关潜在问题的足够详细信息。
公众号: 云原生生态圈
2023/08/23
1.5K0
解密服务性能利器:Pyroscope让你的应用飞起来
开源Web版Linux,数据库,Redis,MongoDB统一管理操作平台Go语言版本
介绍 web版 linux(终端[终端回放] 文件 脚本 进程)、数据库(mysql postgres)、redis(单机 哨兵 集群)、mongo统一管理操作平台 开发语言与主要框架 前端:typescript、vue3、element-plus 后端:golang、gin、gorm 系统相关资料 项目文档: https://objs.gitee.io/mayfly-go-docs 系统操作视频: https://space.bilibili.com/484091081/channel/collectio
开源日记
2023/03/10
1.1K0
开源Web版Linux,数据库,Redis,MongoDB统一管理操作平台Go语言版本
腾讯云 CIF 工程效能峰会,10 月 19 - 20 日震撼来袭!
近年来,依托于云计算的飞速发展,腾讯云云产品更新迅猛,云原生生态构建初具规模,越来越多的企业也开始寻求与深入数字化转型之路。但在摸索与实践中,企业往往会进入“伪上云”的误区。除了单纯的服务器上云,企业更需要在组织方式、技术架构上进行更深刻的变革,才能充分享受云原生带来的种种便利。 腾讯云 CIF 工程效能峰会由腾讯云 CODING 主办,以“云上开发,化繁为简”为主题,聚焦云原生加持下的研发效能升级,与数字化风潮下的企业转型实践。腾讯云副总裁肖衡、中国信息通信研究院云大所副所长栗蔚、腾讯 PCG
腾讯云中间件团队
2021/10/12
3360
腾讯开源业界首个云原生标准的一站式微服务管理框架 Femas
企业数字化向云原生演进过程面临诸多痛点,微服务框架不统一、协议多样化、语言异构,纷繁复杂的微服务技术栈,基础组件之间像一座座孤岛,各个基础组件的控制面不能互联,让用户的体验非常割裂,各种历史包袱阻碍了企业平滑过渡到云原生架构的进程。 为了帮助企业快速平滑转型为云原生微服务架构,腾讯经过多年的探索与创新,正式开源业界首个云原生标准的一站式微服务管理框架 Femas,通过定义一套开放式的微服务控制面标准协议,实现微服务基础组件的统一管理和调度。 数据面基于多运行时的架构设计,基础能力标准化、模块化、灵活可扩展,
腾源会
2022/03/18
9281
重磅|腾讯云开源业界首个 etcd 一站式治理平台 Kstone
在 CNCF 云原生基金会举办的2021年12月9日 KubeCon China大会上,腾讯云容器 TKE 团队发布了 Kstone etcd 治理平台开源项目。 PART ONE Kstone 开源 2021年12月9日,腾讯云容器 TKE 团队发布了 Kstone etcd 治理平台开源项目。Kstone 是腾讯云容器 TKE 团队发起的一个基于 Kubernetes 的云原生一站式 etcd 治理项目。该项目源自腾讯内部大规模 etcd 集群治理和最佳实践,很好的实现了对各类业务场景下的 etc
腾源会
2021/12/13
1.3K0
超硬核图解 Kubernetes 网络
底层网络 Underlay Network 顾名思义是指网络设备基础设施,如交换机,路由器, DWDM 使用网络介质将其链接成的物理网络拓扑,负责网络之间的数据包传输。
公众号: 云原生生态圈
2023/08/23
1.6K0
超硬核图解 Kubernetes 网络
收藏指数满格!腾讯云开发者社区沙龙online全年视频&PPT打包!
回首2020,在各位小伙伴们的支持下,云+社区解锁了很多新的成就。其中,在疫情刚刚肆虐的那段时期,为了响应“停工不停产、停课不停学”的号召,我们以特殊时期的技术变化为主线,发布了名为「技术应变力」的主题沙龙。 首场沙龙一经上线就获得了众多好评,在那段昏暗的日子里带给广大技术人员新的抚慰和希望。而云+社区沙龙online秉持着技术传播的理念,也一直存续了下来。时至今日,我们一共策划了6个主题,举办了52场线上直播,有70位来自腾讯内外各个技术领域的大牛嘉宾分享了他们自身的技术理念和实践干货。 现在,这
腾讯云开发者
2021/01/12
1K0
Serverless 一站式云原生应用开发实践
在国内搜索引擎搜索“Serverless” 会有许多五花八门的答案,有些人认为 Serverless 是前端的 3.0 时代,会给前端开发者带来很好的收益改变。社区也在谈 Serverless,知乎上也有人会问一些问题。当我们谈论 Serverless 时,不禁会有一个疑问,你说的 Serverless 到底是哪个 Serverless?大家对 Serverless 的理解其实是有一些困惑的,通过下面这张搜索引擎的截图大家就可以看到,对于 Serverless 有很多不同的解读。
腾讯云开发者
2020/07/01
3.9K0
2019年MongoDB中文社区年终盛会约你来深圳
2019年MongoDB中文社区年终盛会将于2020年1月4日(星期六)在深圳福田区车公庙附近召开。来现场,您将收获3大专场经验加持:
云加小助手
2019/12/24
1.7K0
2019年MongoDB中文社区年终盛会约你来深圳
GitHub 5.2K Star,多种开发环境管理利器
devbox 是一个由 jetpack-io 开发的开源项目,它是一个用于提高开发效率的工具。通过使用 devbox,开发人员可以在本地快速构建一个完整且隔离的开发环境,并使用各种工具和技术来开发和测试应用程序。以下是具体的一个使用示例:
公众号: 云原生生态圈
2023/08/23
6150
GitHub 5.2K Star,多种开发环境管理利器
嘉为蓝鲸WeOps,国内首个支持国产化的一站式运维平台!
近年来,“华为、中兴”事件及“俄乌战争”引发的科技制裁,给我国信息技术产业敲响警钟,解决核心技术关键环节“卡脖子”的问题刻不容缓。在当今国际形势和国家经济双循环的发展格局下,国家逐步推进科技强国、数字中国等战略部署。在国家相关政策支持下,信息技术应用创新(简称信创)产业加速发展,国内厂商信息技术创新能力正不断提升。
嘉为蓝鲸
2022/09/02
1.3K0
嘉为蓝鲸WeOps,国内首个支持国产化的一站式运维平台!
完整版web前端学习路线图(超详细自学路线)
JavaScript基础+进阶 ➾ Ajxa ➾ JavaScript应用项目实践 ➾ Node.js ➾ MongoDB项目实践
程序狗
2023/03/27
3.9K0
推荐阅读
相关推荐
堪称一站式管理平台,同时支持Linux、MySQL、Redis、MongoDB可视化管理!
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验