【文件操作】-还在为运行的数据没法保存而烦恼吗??这篇博客让你十分钟之内解决问题,赶紧进来看看!!!

news2024/11/12 12:04:26

🎇作者:小树苗渴望变成参天大树
💦作者宣言:认真写好每一篇博客
💖作者gitee:gitee
**加粗样式**

如 果 你 喜 欢 作 者 的 文 章 ,就 给 作 者 点 点 关 注 吧!

✨文件操作

  • 🧨前言
  • 💤一、为什么使用文件操作?
  • 🎊二、什么是文件?
    • 2.1 程序文件
    • 2.2 数据文件
    • 2.3 文件名
  • 💢三、文件的打开和关闭
    • 3.1 文件指针
    • 3.2 文件的打开和关闭
  • 🎉四、 文件的顺序读写
    • 4.1[fgetc](https://legacy.cplusplus.com/reference/cstdio/fgetc/?kw=fgetc)和[fputc](https://legacy.cplusplus.com/reference/cstdio/fputc/?kw=fputc)
    • 4.2[fgets](https://legacy.cplusplus.com/reference/cstdio/fgets/?kw=fgets)和[fputs](https://legacy.cplusplus.com/reference/cstdio/fputs/?kw=fputs)
    • 4.3[fscanf](https://legacy.cplusplus.com/reference/cstdio/fscanf/?kw=fscanf)和[fprintf](https://legacy.cplusplus.com/reference/cstdio/fprintf/?kw=fprintf)
    • 4.4[sscanf](https://legacy.cplusplus.com/reference/cstdio/sscanf/?kw=sscanf)和[sprintf](https://legacy.cplusplus.com/reference/cstdio/sprintf/?kw=sprintf)
    • 4.5解决疑惑
    • 4.6[fwrite](https://legacy.cplusplus.com/reference/cstdio/fwrite/?kw=fwrite)和[fread](https://legacy.cplusplus.com/reference/cstdio/fread/?kw=fread)
  • 🎄五、文件的随机读写
    • 5.1[fseek](https://legacy.cplusplus.com/reference/cstdio/fseek/?kw=fseek)
    • 5.2[ftell](https://legacy.cplusplus.com/reference/cstdio/ftell/?kw=ftell)
    • 5.3[rewind](https://legacy.cplusplus.com/reference/cstdio/rewind/?kw=rewind)
  • 💥六、文本文件和二进制文件
  • 💨七、文件读取结束的判定
    • 7.1被错误使用的feof
  • 💥八、文件缓冲区
  • 💞九、总结


🧨前言

各位友友们,今天我们玩点不一样的东西,我们之前在运行程序后,下次运行的时候之前的数据就不在了,原因是,我们程序在运行的时候,操作的数据都在内存上,程序结束后数据就消失了,那我们怎么讲数据永久保存起来呢??这时候就需要使用文件操作的知识将其永久保存,那我们开始进入正文,来一起感受不一样的知识吧
本章重点

  1. 为什么使用文件
  2. 什么是文件
  3. 文件的打开和关闭
  4. 文件的顺序读写
  5. 文件的随机读写
  6. 文本文件和二进制文件
  7. 文件读取结束的判定
  8. 文件缓冲区

💤一、为什么使用文件操作?

我们在之前运行的所有程序中,发现数据都无法保存下次来,第一次和第二次运行完全是独立的,不能将数据给到下一次运行的程序中,这就涉及到了数据持久化的问题,我们一般数据持久化的方法有,把数据存放在磁盘文件、存放到数据库等方式。

使用文件我们可以将数据直接存放在电脑的硬盘上,做到了数据的持久化。

🎊二、什么是文件?

磁盘上的文件是文件。
但是在程序设计中,我们一般谈的文件有两种:程序文件、数据文件(从文件功能的角度来分类的)。

2.1 程序文件

包括源程序文件(后缀为.c),目标文件(windows环境后缀为.obj),可执行程序(windows环境后缀为.exe)。
在这里插入图片描述
这些是在程序创建的时候就自动生成了这些文件,所以叫程序文件

2.2 数据文件

文件的内容不一定是程序,而是程序运行时读写的数据,比如程序运行需要从中读取数据的文件,或者输出内容的文件。

在这里插入图片描述
这个是使用者自己创建的文件,来存放数据的,所以叫数据文件

在以前各章所处理数据的输入输出都是以终端为对象的,即从终端的键盘输入数据,运行结果显示到显示器上。

其实有时候我们会把信息输出到磁盘上,当需要的时候再从磁盘上把数据读取到内存中使用,这里处理的就是磁盘上文件。

2.3 文件名

一个文件要有一个唯一的文件标识,以便用户识别和引用。
文件名包含3部分:文件路径+文件名主干+文件后缀
例如: c:\code\test.txt
为了方便起见,文件标识常被称为文件名。

绝对路径:将文件的具体路径写出来
C:\2023寒假代码\2023-winter-vacation-code\Contact\tongxunlu.txt

i相对路径:只写成一部分路径,系统会直接找到他具体所在的位置
Contact\tongxunlu.txt

注意:我们一定要打开文件后缀名,防止找不到文件
在这里插入图片描述
如果关闭这个文件后缀名,即使你把文件命名成tongxunlu.txt,那默认打开的是tongxunlu,txt.txt这样的文件,所以我们作为一名专业的程序员,一定要打开我们文件的后缀名,不然我们都不知道我们写的是什么文件了

💢三、文件的打开和关闭

3.1 文件指针

缓冲文件系统中,关键的概念是“文件类型指针”,简称“文件指针”。

每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件的名字,文件状态及文件当前的位置等)。这些信息是保存在一个结构体变量中的。该结构体类型是有系统声明的,取名FILE.

例如,VS2013编译环境提供的 stdio.h 头文件中有以下的文件类型申明:

struct _iobuf {
        char *_ptr;
        int   _cnt;
        char *_base;
        int   _flag;
        int   _file;
        int   _charbuf;
        int   _bufsiz;
        char *_tmpfname;
       };
typedef struct_iobuf FILE;

1.不同的C编译器的FILE类型包含的内容不完全相同,但是大同小异。
2.每当打开一个文件的时候,系统会根据文件的情况自动创建一个FILE结构的变量,并填充其中的信息,使用者不必关心细节。
3.一般都是通过一个FILE的指针来维护这个FILE结构的变量,这样使用起来更加方便。

下面我们可以创建一个FILE*的指针变量:

FILE* pf;//文件指针变量

定义pf是一个指向FILE类型数据的指针变量。可以使pf指向某个文件的文件信息区(是一个结构体变量)。通过该文件信息区中的信息就能够访问该文件。也就是说,通过文件指针变量能够找到与它关联的文件。

例如:
在这里插入图片描述

,我们通过文件指针找到这个文件信息区,将数据放到这个文件信息区,至于怎么把文件信息区的数据放到文件中是通过一个I/O接口来实现连接的,我们使用者不需要关系

3.2 文件的打开和关闭

文件在读写之前应该先打开文件,在使用结束之后应该关闭文件。
(就跟动态开辟一样,我们需要i先开辟,然后使用完需要释放在置为NULL)

在编写程序的时候,在打开文件的同时,都会返回一个FILE*的指针变量指向该文件,也相当于建立了指针和文件的关系。

ANSIC 规定使用fopen函数来打开文件,fclose来关闭文件

//打开文件
FILE * fopen ( const char * filename, const char * mode );
//关闭文件
int fclose ( FILE * stream );

fopen:第一个参数是传你要打开文件名,第二个参数是传你要以什么方式打开这个文件
在这里插入图片描述打开失败会返回一个空指针

fclose:参数是传你要关闭的文件名

打开方式如下:

   文件使用方式           含义                           如果指定文件不存在
   “r”(只读) 为了输入数据,打开一个已经存在的文本文件     出错
   “w“ (只写) 为了输出数据,打开一个文本文件              建立一个新的文件
   “a”(追加) 向文本文件尾添加数据                       建立一个新的文件
   “rb”(只读) 为了输入数据,打开一个二进制文件           出错
   “wb”(只写) 为了输出数据,打开一个二进制文件           建立一个新的文件
   “ab”(追加) 向一个二进制文件尾添加数据                 出错
   “r+”(读写) 为了读和写,打开一个文本文件               出错
   “w+”(读写) 为了读和写,建议一个新的文件               建立一个新的文件
   “a+”(读写) 打开一个文件,在文件尾进行读写             建立一个新的文件
  “rb+”(读写) 为了读和写打开一个二进制文件               出错
  “wb+”(读写) 为了读和写,新建一个新的二进制文件          建立一个新的文件
  “ab+”(读写) 打开一个二进制文件,在文件尾进行读和写      建立一个新的文件

实例代码:

#include<stdio.h>
int main()
{
	FILE* pf = fopen("test.txt", "w");//以只写的形式打开test.txt文件
	if (NULL == pf)
	{
		perror("fopen:");//打开失败的情况
	}
	else
	{
		printf("打开成功!\n");
		fclose(pf);
		pf = NULL;//因为pf也是指针,关闭文件后,pf里面存放的还是文件信息区的地址,不置空,就会变成野指针没可能会出现大问题
	}
	return 0;
}

在这里插入图片描述

我只是程序启动的时候,没有这个文件就自动会创建一个这样的文件,如果你打开失败,你可以到你的项目目录下自己创建一个你想要打开的文件就可以了

接下来我们通过一下函数来具体看看怎么把数据放到已经打开的文件里面去.

🎉四、 文件的顺序读写

在这里插入图片描述

4.1fgetc和fputc

在这里插入图片描述

fputc的例子:

int main()
{
	FILE* pf = fopen("test.txt", "w");//以只写的形式打开test.txt文件
	if (NULL == pf)
	{
		perror("fopen:");//打开失败的情况
	}
	else
	{
		int ch = fputc('a', pf);
		printf("%c ", ch);
		ch = fputc('b', pf);
		printf("%c ", ch);
	    ch = fputc('c', pf);
		printf("%c ", ch);
		fclose(pf);
		pf = NULL;
	}
	return 0;
}

在这里插入图片描述

fgetc的例子:

int main()
{
	FILE* pf = fopen("test.txt", "r");//以只读的形式打开test.txt文件
	if (NULL == pf)
	{
		perror("fopen:");//打开失败的情况
	}
	else
	{
		int ch = fgetc(pf);
		printf("%c ", ch);
		fclose(pf);
		pf = NULL;
	}
	return 0;
}

在这里插入图片描述

我们使用fputc是使用只写的方式打开文件,使用fgetc是只读的方式打开文件,一定要注意文件的打开方式。

我们在使用fputc写数据进去的时候是顺序读写,所以看到文件里面的数据是连续存放的,在使用fgetc的时候,读取完一个字符后,指针会自动指向下一个字符的,怎么判断读取结束呢??后面会介绍这个函数来判断文件里面是否还有数据

通过例子,我们也知道了;这两个函数为啥叫字符输入输出函数了吧,他们是针对字符来进行输入输出的。

4.2fgets和fputs

在这里插入图片描述

fputs的例子:

int main()
{
	FILE* pf = fopen("test.txt", "w");//以只写的形式打开test.txt文件
	if (NULL == pf)
	{
		perror("fopen:");//打开失败的情况
	}
	else
	{
		fputs("nihao", pf);
        //fputs("nihao\n", pf);
		fputs("youyoumen", pf);
		fclose(pf);
		pf = NULL;
	}
	return 0;
}

在这里插入图片描述
fgets的例子:

int main()
{
	FILE* pf = fopen("test.txt", "r");//以只写的形式打开test.txt文件
	if (NULL == pf)
	{
		perror("fopen:");//打开失败的情况
	}
	else
	{
		char buf[20] = { 0 };
		fgets(buf, 5, pf);
		printf("%s\n", buf);
		fgets(buf, 6, pf);
		printf("%s", buf);
		fclose(pf);
		pf = NULL;
	}
	return 0;
}

在这里插入图片描述
我们发现我们明明读取的是5个字符却打印了四个字符,原因是我们后面会读取到一个\0放在字符串后面,所以看到的字符比我们想要永远要少一个,我们看文档也可以发现这个现象。并且要创建能存放的下我们读取出来数据的数组
在这里插入图片描述

如果文件你们的数据有好多行,每一行只有4个字符,我想要读取10个字符,不会读取到第二行的数据,只会读取第一行的数据,即使第二行没到我们想要的字符个数我们也不在读取了.大家下去可以自己去测试一下,所以我们这两个函数也叫文本行输入输出函数

4.3fscanf和fprintf

在这里插入图片描述

fprintf的例子:

struct stu
{
	char name[20];
	int age;
	float sorce;
};
int main()
{
	FILE* pf = fopen("test.txt", "w");//以只写的形式打开test.txt文件
	if (NULL == pf)
	{
		perror("fopen:");//打开失败的情况
	}
	else
	{
		struct stu s = { "zhangsan",20,95.5 };
		fprintf(pf, "%s %d %lf", s.name, s.age, s.sorce);
		fclose(pf);
		pf = NULL;
	}
	return 0;
}

在这里插入图片描述
fscanf的例子:

struct stu
{
	char name[20];
	int age;
	float sorce;
};
int main()
{
	FILE* pf = fopen("test.txt", "r");//以只读的形式打开test.txt文件
	if (NULL == pf)
	{
		perror("fopen:");//打开失败的情况
	}
	else
	{
		struct stu tmp = { 0 };
		fscanf(pf, "%s %d %f", tmp.name, &(tmp.age), &(tmp.sorce));
		printf("%s %d %f", tmp.name, tmp.age, tmp.sorce);
		fclose(pf);
		pf = NULL;
	}
	return 0;
}

在这里插入图片描述
我们发现可以把数据按照格式化的形式输入输出,用法和scanf、printf一样,只是多了一个参数,大家下来可以测试更多的数据。

4.4sscanf和sprintf

在这里插入图片描述
sprintf的例子:

struct stu
{
	char name[20];
	int age;
	float sorce;
};
int main()
{
	
	struct stu tmp = { "zhangsan",20,95};
	char buf[100] = { 0 };
	sprintf(buf, "%s %d %f", tmp.name, tmp.age, tmp.sorce);
	printf("%s", buf);
	
	return 0;
}

在这里插入图片描述
sscanf的例子:

struct stu
{
	char name[20];
	int age;
	float sorce;
};
int main()
{
	
	struct stu tmp = { "zhangsan",20,95};
	char buf[100] = { 0 };
	sprintf(buf, "%s %d %f", tmp.name, tmp.age, tmp.sorce);
	printf("%s\n", buf);
	struct stu s = { 0 };
	sscanf(buf, "%s %d %f", s.name, &(s.age), &(s.sorce));
	printf("%s %d %f", tmp.name, tmp.age, tmp.sorce);
	return 0;
}

在这里插入图片描述

这两个函数只针对字符串的输入输出,和文件操作没有什么关系,目的是与之前的形成对比。

对比一组函数:

scanf/fscanf/sscanf
printf/fprintf/sprintf
   scanf:从键盘上读取格式化的数据
   printf:把数据按格式化输出到屏幕上

   fscanf:针对所有输入流的格式化的输入函数
   fprintf:针对所有输出流的格式化的输出函数

   sscanf:从一个字符串还原出一个格式化的数据
   sprintf:把格式化的数据存放在(转换成)字符串中

希望通过这个让大家充分理解函数之间的差异和相似性,能更好的运用这些函数。

4.5解决疑惑

一、为什么写文件使用fgetc,fgets,fprintf,读文件使用fgetc,fgets,fscanf
和我们的习惯刚好反过来了,让我们使用起来非常别扭,接下来我们来解释一下
在这里插入图片描述

现在应该可以明白了,把主体都看成内存就可以很好的理解了

二、细心的小伙伴有没有发现我在介绍上面函数的时候总喜欢把文件说成文件流,为什么我要这么说呢?还有使用关于所有输入输出流是什么意思呢?接下来我为大家讲解一下
在这里插入图片描述

我们以fprintf和fscanf为例:

struct stu
{
	char name[20];
	int age;
	float sorce;
};
int main()
{
		struct stu tmp = { 0 };
		fscanf(stdin, "%s %d %f", tmp.name, &(tmp.age), &(tmp.sorce));
		fprintf(stdout,"%s %d %f", tmp.name, tmp.age, tmp.sorce);
	return 0;
}

在这里插入图片描述
大家可以下去自己测试一下fgetc、fputc和fgets、fputs这两组函数,这六个函数可以实现所有流的输入输出,这里面只是举出来这两个例子,

我们上面说的六个函数,存放在文件中是我们看得懂的信息,所以也叫文本信息,将下来我们将讲解一下用二进制的方式把数据放到文件当中,应该怎么去做。

4.6fwrite和fread

在这里插入图片描述

fread,fwrite:第一个参数:指向内存块的指针,其大小至少为(sizecount)字节,转换为voi d
第二个参数:每个元素的大小
第三个参数:要传几个元素
第四个参数:要传的文件流

fwrite的例子:

struct stu
{
	char name[20];
	int age;
	float sorce;
};
int main()
{
	FILE* pf = fopen("test.txt", "wb");//以二进制的方式写入
	if (NULL == pf)
	{
		perror("fopen:");
		return 1;
	}
	struct stu s = { "张三",20,95 };
	fwrite(&s, sizeof(s), 1, pf);
	fclose(pf);
	pf = NULL;
	return 0;
}

在这里插入图片描述
fread的例子:

struct stu
{
	char name[20];
	int age;
	float sorce;
};
int main()
{
	FILE* pf = fopen("test.txt", "rb");//以二进制的方式读出
	if (NULL == pf)
	{
		perror("fopen:");
		return 1;
	}
	struct stu tmp = { 0};
	fread(&tmp, sizeof(tmp), 1, pf);
	printf("%s %d %f", tmp.name, tmp.age, tmp.sorce);
	fclose(pf);
	pf = NULL;
	return 0;
}

在这里插入图片描述

我们通过上面的代码可以理解了这两个函数的用法了,大家可以下去自己多测试几组数据

至此我们介绍完了文件的顺序读写,接下来我们将介绍文件的随机读写

🎄五、文件的随机读写

5.1fseek

根据文件指针的位置和偏移量来定位文件指针

在这里插入图片描述
我们在之前介绍过fgetc是字符读取函数,读取一个字符,文件指针就会指向下一个字符,但是我们想读取前面已经读取到的数据咋办呢?就需要想文件指针的位置移到我们想要数据的位置,我们先看代码在来分析:

int main()
{
	FILE* pf = fopen("test.txt", "r");//以只读的方式打开
	if (NULL == pf)
	{

		perror("fopen");
		return 1;
	}
	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
	//此时我们文件指针已经指向字符d,在读取就会打印字符d
	//如果我们想要再次读取字符b,就需要调整指针的位置
	fseek(pf, -2, SEEK_CUR);
	//fseek(pf, 1, SEEK_SET);
	//fseek(pf, -4, SEEK_END);
	ch = fgetc(pf);
	printf("%c\n", ch);//b
	return 0;
}

在这里插入图片描述

我们可以看到fseek确实可以改变我们文件指针的位置,实现随机性,万一文件里面的数据很多,使用者不知道指针偏移到那个位置了,我们可不可以计算他的位置呢??答案是可以的,接下来介绍ftell

5.2ftell

返回文件指针相对于起始位置的偏移量 

在这里插入图片描述

在这里插入图片描述

接下来在将一个函数,目的是让文件指针回到起始位置

5.3rewind

 让文件指针的位置回到文件的起始位置

在这里插入图片描述

在这里插入图片描述

也可以使用fseek函数来实现这个功能:
在这里插入图片描述

我们可以把这三个函数一起来理解

💥六、文本文件和二进制文件

根据数据的组织形式,数据文件被称为文本文件或者二进制文件
数据在内存中以二进制的形式存储,如果不加转换的输出到外存,就是二进制文件。
如果要求在外存上以ASCII码的形式存储,则需要在存储前转换。以ASCII字符的形式存储的文件就是文本文件

一个数据在内存中是怎么存储的呢?

字符一律以ASCII形式存储,数值型数据既可以用ASCII形式存储,也可以使用二进制形式存储。
如有整数10000,如果以ASCII码的形式输出到磁盘,则磁盘中占用5个字节(每个字符一个字节),而二进制形式输出,则在磁盘上只占4个字节(VS2019测试)。

在这里插入图片描述
我们通过在文件里面看看二进制数据,测试代码:

#include <stdio.h>
int main()
{
 int a = 10000;
 FILE* pf = fopen("test.txt", "wb");
 fwrite(&a, 4, 1, pf);//二进制的形式写到文件中
 fclose(pf);
 pf = NULL;
 return 0;
}

运行结果:
在这里插入图片描述
我们是看不懂的,我们把这个文件以二进制的方式打开看看里面的内容会被翻译成什么样子:

查看方式
在这里插入图片描述
结果为:
在这里插入图片描述
以十六进制消失方便我们去查看数据,这个代表的就是10000

我们通过文件来看看文本文件:
在这里插入图片描述

这时候就能更好的理解文本文件和二进制文件了吧

💨七、文件读取结束的判定

7.1被错误使用的feof

牢记:在文件读取过程中,不能用feof函数的返回值直接用来判断文件的是否结束。
而是应用于当文件读取结束的时候,判断是读取失败结束,还是遇到文件尾结束

  1. 文本文件读取是否结束,判断返回值是否为 EOF ( fgetc ),或者 NULL ( fgets )
    例如:
    ==fgetc 判断是否为 EOF ==.
    fgets 判断返回值是否为 NULL .
  2. 二进制文件的读取结束判断,判断返回值是否小于实际要读的个数。
    例如:
    fread判断返回值是否小于实际要读的个数。

意思就是feof是判断结束是由什么原因导致的

正确的使用:
文本文件的例子:

#include <stdio.h>
#include <stdlib.h>
int main(void)
{
    int c; // 注意:int,非char,要求处理EOF
    FILE* fp = fopen("test.txt", "r");
    if(!fp) {
        perror("File opening failed");
        return EXIT_FAILURE;
   }
 //fgetc 当读取失败的时候或者遇到文件结束的时候,都会返回EOF
    while ((c = fgetc(fp)) != EOF) // 标准C I/O读取文件循环
   { 
       putchar(c);
   }
   //判断是什么原因结束的
    if (ferror(fp))//如果是文件读取的时候出错结束,ferror为真
        puts("I/O error when reading");
    else if (feof(fp))//如果是到文件尾结束,feof为真
        puts("End of file reached successfully");
    fclose(fp);
}

二进制文件的例子:

#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 的数组
    fclose(fp);
    double b[SIZE];
    fp = fopen("test.bin","rb");
    size_t ret_code = fread(b, sizeof *b, SIZE, fp); // 读 double 的数组
    if(ret_code == 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))
          printf("Error reading test.bin: unexpected end of file\n");
       else if (ferror(fp)) {
           perror("Error reading test.bin");
       }
   }
    fclose(fp);
}

所以大家不要错误使用feof,不敢让大家笑话啊

💥八、文件缓冲区

ANSIC 标准采用“缓冲文件系统”处理的数据文件的,所谓缓冲文件系统是指系统自动地在内存中为程序
中每一个正在使用的文件开辟一块“文件缓冲区”。从内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘上。如果从磁盘向计算机读入数据,则从磁盘文件中读取数据输入到内存缓冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(程序变量等)。缓冲区的大小根据C编译系统决定的。

在这里插入图片描述
我们不能直接将数据放到硬盘或者文件当中去,我们需要把文件放到缓冲区,集中在一起放到硬盘或者文件中去,那缓冲区什么时候放数据到硬盘或者文件当中呢??

一、缓冲区的已满
二、主动刷新一下

因为缓冲区在内存中没法直观给你们看到,但我们通过代码来证明缓冲区确实存在:

#include <stdio.h>
#include <windows.h>
//VS2019 WIN11环境测试
int main()
{
 FILE*pf = fopen("test.txt", "w");
 fputs("abcdef", pf);//先将代码放在输出缓冲区
 printf("睡眠10秒-已经写数据了,打开test.txt文件,发现文件没有内容\n");
 Sleep(10000);
 printf("刷新缓冲区\n");
 fflush(pf);//刷新缓冲区时,才将输出缓冲区的数据写到文件(磁盘)
 //注:fflush 在高版本的VS上不能使用了
 printf("再睡眠10秒-此时,再次打开test.txt文件,文件有内容了\n");
 Sleep(10000);
 fclose(pf);
 //注:fclose在关闭文件的时候,也会刷新缓冲区
 pf = NULL;
 return 0;
}

在这里插入图片描述
我们可以看到数据没有立马写进文件,使用fflush主动刷新一下,才放到文件中,

这里可以得出一个结论:
因为有缓冲区的存在,C语言在操作文件的时候,需要做刷新缓冲区或者在文件操作结束的时候关闭文件。
如果不做,可能导致读写文件的问题。

💞九、总结

今天关于文件操作的知识博主就先分享到这了,还希望读者可以下去将这些知识好好理解一遍,接下来我会更新一个小项目,把前面学到的结构体,动态内存管理,加上文件操作,这些知识应用到实战上面,让我们也充分体会这些知识是怎么被我们串联在一起,让我们一起下一篇博客带给大家的惊喜。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/172702.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

压力测试和JMeter使用分析

压力测试考察当前软硬件环境下系统所能承受的最大负荷并帮助找出系统瓶颈所在。 压测都 是为了系统在线上的处理能力和稳定性维持在一个标准范围内&#xff0c;做到心中有数。 使用压力测试&#xff0c;我们有希望找到很多种用其他测试方法更难发现的错误。 有两种错误类型是:…

nginx简单梳理

Nginx总结 这里写目录标题Nginx总结**Nginx** **的简介**1、什么是 **nginx**2、正向代理3、反向代理4、负载均衡**5**、动静分离**Nginx** 的安装**Nginx** **的常用的命令****Nginx** 的配置文件**Nginx** **配置实例**-**反向代理实例** **1****Nginx** **配置实例**-**负载…

408—栈,队列和数组

stl里面的栈中没有清空的函数&#xff0c; 需要自己编写函数清空&#xff08;while循环返回pop&#xff09;&#xff0c; 更常见的做法是重新定义一个栈&#xff0c;这样的时间复杂度就是O(1)栈的基本操作&#xff0c;出栈入栈判空和求栈的长度,和取栈顶元素以及清空出栈和取栈…

初学者C语言练习题-函数

二、函数 一个C程序有且只有一个主函数&#xff0c;即main函数。 C程序就是执行主函数里的代码&#xff0c;也可以说这个主函数就是C语言中的唯一入口。而main前面的int就是主函数的类型.printf()是格式输出函数&#xff0c;这里就记住它的功能就是在屏幕上输出指定的信息retur…

MATLAB-自动控制原理-控制系统的数学模型

目录 一、利用MATLAB进行数学模型转换 语法&#xff1a; 例&#xff08;将传递函数写成零极点的形式&#xff09;&#xff1a; 例&#xff08;将传递函数写成因子式的形式&#xff09;&#xff1a; 二、利用MATLAB求系统传递函数 串联等效&#xff1a; 并联等效&#xf…

uboot启动流程详细分析(基于i.m6ull)

uboot介绍 uboot就是一段引导程序&#xff0c;在加载系统内核之前&#xff0c;完成硬件初始化&#xff0c;内存映射&#xff0c;为后续内核的引导提供一个良好的环境。uboot是bootloader的一种&#xff0c;全称为universal boot loader。 一、uboot的makefile 1.1 makefile整…

ccc-sklearn-16-XGBoost(2)

文章目录XGBoost的其他参数选择弱评估器&#xff1a;参数boosterXGB的目标函数&#xff1a;参数objectiveXGB目标函数的求解参数化决策树ftf_tft​&#xff1a;参数alpha&#xff0c;lambda寻找最佳树结构&#xff1a;求解w和T寻找最佳分枝&#xff1a;结构分数之差让树停止生长…

C++ 函数重载:女友说的话到底是什么意思?

&#x1f451;专栏内容&#xff1a;C学习笔记⛪个人主页&#xff1a;子夜的星的主页&#x1f495;座右铭&#xff1a;日拱一卒&#xff0c;功不唐捐 目录一、前言二、函数重载1、函数重载概念2、函数重载的分类Ⅰ、参数类型不同Ⅱ、参数个数不同Ⅲ、参数类型顺序不同3、函数重载…

vs code,platform下载Arduino程序到ESP8266,并传送文件到flash

参考视频&#xff1a;https://www.bilibili.com/video/BV1yR4y1X72D/ 首先要知道 存储空间中有程序的存储地址和文件存储地址&#xff0c;可以对单独一个部分的写入不影响另一部分内容。 vs code 的platformIO插件进行程序和文件的上传 基本创建工程和程序可以参考&#x…

启明欣欣STM32开发板移植FreeRTOS

承接这篇文章&#xff0c;本篇讲述如何把FreeRTOS移植到启明欣欣STM32开发板里&#xff0c;比较简单&#xff0c;网上也有各种教程&#xff0c;本文也是参考其它文章&#xff0c;这里再记录一下。 一 搭建基础工程 启明欣欣STM32开发板上的MCU是STM32F407ZGT6&#xff0c;根据…

智能电视机安装App

每年的12月18日是世界电视机日&#xff0c;电视机诞生于1925年&#xff0c;最初是电子机械式电视机&#xff1b;到了1933年&#xff0c;诞生CRT电视&#xff0c;即黑白电视&#xff0c;它只有黑色或白色&#xff0c;看任何物品都是黑色或者白色。又过了20年&#xff0c;1953年彩…

Java之collection集合、常见数据结构、List和泛型

目录集合概述总结Collection集合的体系特点总结Collection集合常用APICollection集合的遍历方式方式一&#xff1a;迭代器总结方式二&#xff1a;foreach/增强for循环方式三&#xff1a;lambda表达式Collection集合存储自定义类型的对象总结常见数据结构数据结构概述、栈、队列…

【C++初阶】C++基础(一)

C是在C的基础之上&#xff0c;容纳进去了面向对象编程思想&#xff0c;并增加了许多有用的库&#xff0c;以及编程范式等。熟悉C语言之后&#xff0c;对C学习有一定的帮助&#xff0c;本文主要目标&#xff1a;1. 补充C语言语法的不足&#xff0c;以及C是如何对C语言设计不合理…

尚医通-首页显示-前端数据整合(二十六)

目录&#xff1a; &#xff08;1&#xff09;前台用户系统-首页显示-整合静态页面 &#xff08;2&#xff09;前台用户系统-首页显示-数据接口开发 &#xff08;3&#xff09;前端用户系统-首页显示-前端整合 &#xff08;1&#xff09;前台用户系统-首页显示-整合静态页面 …

代码随想录第七天(541、剑指05)

文章目录541. 反转字符串 II发现了三个基础知识的问题看答案改进剑指 Offer 05. 替换空格答案方法1答案方法2知识点一、二、三、总结541. 反转字符串 II 发现了三个基础知识的问题 第一个 这个题目发现了一个非常大的问题&#xff0c;有点不知道自己的Java基础到底有多少窟窿…

C++ 20 新特性 ranges 精讲

C 20 新特性 ranges 精讲 C20 中的 ranges 库使得使用 STL 更加舒适和强大。ranges 库中的算法是惰性的&#xff0c;可以直接在容器上工作&#xff0c;并且可以很容易地组合。简而言之&#xff0c;ranges 库的舒适性和强大性都源于它的函数思想。 在深入细节之前&#xff0c;…

程序员的7个被动收入途径——我如何每月赚 5万

每个人都想过时间和财富自由的生活&#xff0c;世界上有70亿人&#xff0c;但只有不到18000人能做到这一点&#xff0c;大多数人一生都在为钱工作。 研究表明&#xff0c;全世界65.8万富人至少有三种收入来源&#xff0c;而且都是被动收入。换句话说&#xff0c;大多数富人知道…

Create Realtime-chat app

Tech:React,Node.js,Socket.io,MongoDB styled-component ​​​​​​​ 目录 Base setup Register funcitonality Login funcitonality set Avatar/profile picture Chat container setup useEffect basic hook ChatHeader ChatInput ChatMessage Set socket an…

I.MX6ULL裸机开发笔记2:镜像文件

目录 一、boot ROM程序 二、镜像文件五要素 三、芯片手册 四、芯片手册数据解读 1、空偏移 2、IVT表 3、DCD表 一、boot ROM程序 选择内部启动方式&#xff0c;启动boot ROM程序 初始化时钟&#xff0c;外部DDR3从外部存储介质加载代码 boot ROM程序是芯片厂…

十五天学会Autodesk Inventor,看完这一系列就够了(十一),放样和螺旋扫掠(绘弹簧)

众所周知&#xff0c;Autocad是一款用于二维绘图、详细绘制、设计文档和基本三维设计&#xff0c;现已经成为国际上广为流行的绘图工具。Autodesk Inventor软件也是美国AutoDesk公司推出的三维可视化实体模拟软件。因为很多人都熟悉Autocad&#xff0c;所以再学习Inventor&…