初识C语言·文件操作

目录

1 关于文件

i)文件的基本知识

ii)数据文件的分类

2 文件打开和关闭

i)流和标准流

ii)文件指针

iii)文件打开和关闭

3 文件的顺序读写

i) fgetc fputc

ii) fgets fputs

iii) fscanf fprintf

iv) fwrite fread

4 对比一组函数 scanf/fscanf/sscanf/printf/fprintf/sprintf  

5 文件的随机读写

6 文件读取结束的判定

7 文件缓冲区


1 关于文件

i)文件的基本知识

在电脑中文件是随处可见的,那你思考过为什么存在“文件”吗?当我们运行程序的时候,程序一旦结束,在内存中存储的数据也会被销毁,我们如果想要保存数据,以方便下一次使用的话,就需要用到文件,也就是说,文件是可以用来保存数据的

那什么是文件呢?从文件的功能性分类的话,文件可以分为程序性文件和数据文件程序性文件包括源文件(.c后缀),目标文件(windows后缀为.obj),可执行程序(windows后缀为.exe),我们本章着重介绍的是数据文件,程序文件会在后面的预编译章节介绍。在之前的章节我们处理数据的输入输出都是在终端处理的,如键盘,电脑屏幕,但有点时候我们会把信息输入到磁盘里面,读取数据的时候让磁盘输入数据给内存,在从内存中读取数据,计算机读取数据分为好几个等级,从速度快慢分为寄存器,缓存,内存,硬盘等等,那么本场要学习的就是如何从磁盘从读取数据。

要使用文件,我们肯定要知道文件标识是由什么组成的,⽂件名包含3部分:⽂件路径+⽂件名主⼲+⽂件后缀,例如c:\code\test.txt,就是一个完整的文件名,文件路径是c:\code\,文件名主干是test,文件后缀就是txt,为了方便起见,我们一般把文件标识称作为文件名。

ii)数据文件的分类

数据文件被分为二进制文件文本文件,有的文件创建好了之后不是给使用者看的,是给计算机看的,但是计算机只能识别二进制的1 0,所以会有二进制文件,那么同理可得,文本文件就是给使用者看的,如果当你使用了记事本打开一个文件发现全是乱码,那么它八九不离十的是二进制文件了。

二进制文件是数据在内存中不加转化,直接输出到外存的文件,数据文件需要经过ASCII码值的转化,再输出到外存,所以以ASCII码值存储的文件都是文本文件。

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

字符一律以ASCII码值的形式存储,数值类型的数据可以用二进制的形式存储也可以用ASCII码值的形式存储,以10000来举个例子,10000的二进制是这样的,(VS2019测试)如果直接以二进制的形式存储,就只会占4个字节,如果是ASCII码值的形式存储,那么就会占5个字节,1占一个字节,其余的每个0占一个字节

00000000 00000000 00100111 00010000

当我们使用二进制存储的时候,10000的二进制存储就会变为00 00 27 10,那么因为VS是小端存储,所以屏幕上看到的就是10 27 00 00

int main()
{
	int a = 10000;
	FILE* pf = fopen("data.txt", "wb");
	fwrite(&a, 4, 1, pf);
	fclose(pf);
	pf = NULL;
	return 0;
}

使用fwrite函数创建该文件,并且以二进制的形式存入,最后我们使用二进制的方式打开该文件,得到的就是:

2 文件打开和关闭

i)流和标准流

计算机输出数据和输入数据的时候需要外接到同设备,而通过不同的外接设备输入输出的数据的时候操作都不一样,那么计算机为了简化这一过程,就引用了流的概念,可以理解为计算机将数据不管三七二十一的一股脑给丢进去一个地方,计算机需要数据的时候就去里面拿就行了,那个地方就是流,C语言一般画面,文件,键盘的输入输出的时候都是通过流完成的,那么我们要使用流或者是输入数据到流里面,就需要打开流,使用完再关闭流。

可是实际上我们之前写代码的时候并没有过打开流关闭流这个操作,这是因为C语言默认打开了三个流,这三个流被称为标准流,stdin,stdout,stderr

stdin被称为标准输入流,大多数情况从键盘输入,scanf使用的时候就需要使用到这个流。

stdout被称为标准输出流,大多数情况从屏幕输出,printf使用的时候就需要使用到这个流。

stderr被称为标准错误流,大多数情况写也是从屏幕输出的。

当然,流也是由类型的,这三个流的类型是FILE*,FILE的英文意思就是文件,也就是文件指针,C语言中,FILE*的使用也是用来维护各种流的使用的。

ii)文件指针

文件类型指针就是FILE*,简称文件指针,而每个使用的文件在内存中都开辟了一块文件信息区,文件的相关信息,而这些信息保存在一个结构体变量里面,这个结构体变量就是FILE*,在vs2013关于FILE*的声明是这样的:

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

   创建了一个结构体变量_iobuf,最后重命名为了FILE,而在VS2022声明就没有那么详细了,VS2022的的声明如下:

当然我们只需要关心怎么用FILE*就行,至于文件指针的源码,是不用了解那么多的,我们使用FILE*访问文件信息区的时候就可以找到文件的相关信息,也就是说我们可以利用文件指针间接找到与该文件相关的文件

iii)文件打开和关闭

 文件打开的时候会返回一个指针指向该文件的文件信息区,也就是建立了指针和文件的关系,那么我们使用完之后就应该关闭文件,C语言中打开文件使用的是fopen函数,关闭文件使用的是fclose函数,f就是file,open就是打开的意思,close就是关闭的意思。

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

这是他们的参数,fopen的第一个参数就是文件名,第二个是打开模式,fclose参数就是文件指针,也就是用来接受fopen函数返回的文件指针。

文件的打开模式有许多种,如下:

模式有很多种,感兴趣可以自行使用一下。注意如果文件不存在的话,就会创建一个这样的文件放在该代码的路径下,这是相对路径,如果想要指定路径放的话,就是绝对路径:

	FILE* pf = fopen("C:\\Users\\users\\OneDrive\\data.txt", "w");

只需要在文件名前面加上文件路径就行了,但是要注意的是\要写两个,这是前面转义字符的知识,为了防止\和其他字符结合形成转义字符。

但是多次是用"w"打开文件的时候,每次打开都会先让文件里面的内容清空,这个小现象需要注意一下。


3 文件的顺序读写

i) fgetc fputc

fgetc是字符输入函数,fputc是字符输出函数,均适用于所有文件输入输出流。

int main()
{
	FILE* pf = fopen("data.txt", "w");
	assert(pf);
	char array[26] = { 0 };
	for (int i = 0; i < 26; i++)
	{
		fputc('a' + i, pf);
	}
	for (int j = 0; j < 26; j++)
	{
		array[j] = fgetc(pf);
	}
	for (int j = 0; j < 26; j++)
	{
		printf("%c ", array[j]);
	}
	fclose(pf);
	pf = NULL;
	return 0;
}

 我们创建好文件指针之后,需要判断一下指针是不是空指,最后还要关闭指针,并且置为空指针,这里和动态开辟函数类似,我们给文件里面存好数据之后,第一遍是打印不出来我们想要的26个字符的,因为这里的文件打开模式是w,是写入,那么运行第二次时,我们把w换成r就fgetc函数就开始操作了。

如果fgetc函数读取失败返回或者是读取到了文件尾就会返回eof,也就是文件结束标志,那么函数就结束了,如果fputc写入失败的话也是返回的eof。

在读取文件的时候,字符函数都是一个字符一个字符的读取或者写入的,当读取完一个字符后,光标往后移动,指向下一个字符,所以如果不用for循环的话,想要打印就需要重复写这两行代码:

	int ch = fgetc(pf);
	printf("%c ", ch);

实际上fgetc函数等效于getc函数,只是getc函数在库中可以等效为宏。


ii) fgets fputs

fgets是文本行输入函数,fputs是文本行输出函数,均适用于所有输入输出流,文本行其实就是字符串。

fgets和gets函数是非常不像的,fgets函数有三个参数:

char * fgets ( char * str, int num, FILE * stream );

fgets函数会从流里面读取num -1个字符,并将这些字符存到指针str里面,且最后一个元素置为\0,读取过程中如果碰到了换行符 文件末尾 或者是读取了num - 1个字符,以先到者为准,读取num - 1个字符,第num个字符是\0,如果读取失败,返回的是空指针,如果读着读着莫名读取到了文件尾,那么返回的就是eof。

fputs就没有什么好介绍的了,就是将字符串放进去而已,puts输出之后会自动换行,fputs不会,这是他们的区别。

参考代码:

int main(){
	FILE* pf = fopen("data.txt", "r");
	assert(pf);
	char arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	fputs("xxxxxxx", pf);
	fgets(arr, 6, pf);
	for (int i = 0; i < 6; i++)
	{
		printf("%c ", arr[i]);
	}
	return 0;
}

iii) fscanf fprintf

fscanf fprintf这两个函数是格式化输入输出函数,也就是要用到占位符,适用于所有流,可以这么说scanf能做的,fscanf都可以做,fprintf同理,fscanf就比scanf多了一个参数,fscanf是从文件中读取数据,如果第一个参数是stdin,也就是标准输入流的话,就是从键盘里面输入数据了,fprintf同理可得,如果第一个参数是stdout,也就是标准输出流的话,就是从屏幕上打印,这是函数原型:

int fscanf ( FILE * stream, const char * format, ... );
int fprintf ( FILE * stream, const char * format, ... );
int main()
{
	FILE* pf = fopen("data.txt", "r");
	assert(pf);
	char ch = 0;
	//fputs("1 2 3 4 5 6 7 8 9 10", pf);
	fscanf(pf, "%c",&ch);
	printf("%c", ch);
    fclose(pf);
    pf = NULL;
	return 0;
}

这就是从文件里面读取数据,如果我们想要从键盘读取,只需把流换成stdin就行了,那么这是读文件的操作,如果是写文件,就可以用到fprintf:

int main()
{
	struct St 
	{
		int age;
		char name[20];
		double score;
	};
	FILE* pf = fopen("data.txt", "r");
	assert(pf);
	struct St st = { 10,"zhangsan",99.9};
	fscanf(pf, "%d %s %lf", &(st.age), st.name, &(st.score));
	fprintf(stdout, "%d %s %.1f", st.age, st.name, st.score);
	fclose(pf);
	pf = NULL;
	return 0;
}

iv) fwrite fread

fwrite fread是二进制输入输出函数,只适用于文件    

 这是cplusplus里面的记述,fwrite有四个参数,意思就是从流里面写进去count个大小为size的元素,用到的是指针,文章最开始就用了这个函数,存的是10000,因为只用存一个10000,所以第三个参数是1,fread同理可得。

因为是二进制输入输出函数,所以写入的时候用到的是wb,读取的时候用到的是rb:

int main()
{
	FILE* pf = fopen("data.txt", "wb");
	struct St
	{
		int age;//10
		char name[20];//zhangsan
		double score;//99.9
	}st = {10,"zhangsan",99.9};
	fwrite(&st,sizeof(st),1,pf);
	fclose(pf);
	pf = NULL;
	return 0;
}

这是我们用二进制的方式写进了文件里面:

文本文件写进去是这样的:

可以看到有明显的差别,因为字符都是以ASCII码值的形式存储,所以结果不变,但是其他数据就变化大了,当然我们是看不懂的,计算机看得懂,比如用fread函数就看懂了:

int main()
{
	FILE* pf = fopen("data.txt", "rb");
	struct St
	{
		int age;//10
		char name[20];//zhangsan
		double score;//99.9
	}st;
	fread(&st, sizeof(st), 1, pf);
	printf("%d %s %lf", st.age, st.name, st.score);
	fclose(pf);
	pf = NULL;
	return 0;
}

4 对比一组函数 scanf/fscanf/sscanf/printf/fprintf/sprintf  

scanf printf都是标准流的格式化函数,fscanf fprintf是所有流的格式化函数,scanf printf能做的

fscanf fprintf都可以做,可以理解为fscanf fprintf包含了scanf printf,前面介绍了这两组函数,这里就不介绍了

sscanf sprintf:

sprintf的作用是将格式化的数据放到指针指向的空间里面,sscanf的作用是从指针指向的空间种读取格式化的数据(代码如下):

int main()
{
	struct XY
	{
		char name[10];
		int age;
		float score;
	}xy = {"ziyou",18,100.8};
	char arr[100] = { 0 };
	sprintf(arr, "%s %d %f", xy.name, xy.age, xy.score);
	printf("%s", arr);
	return 0;
}

创建好一个结构体变量之后,再创建一个字符数组用来存放sprintf输出的数据,那么格式化的占位符是必不可少的,因为数组名是首元素地址,也就是指针,所以写上了arr,最后打印出来如下:

因为我在fprintf写参数的时候已经空格了,空格也会输出进去,所以打出来也是带空格的。

int main()
{
	struct XY
	{
		char name[10];
		int age;
		float score;
	}xy = { "zhangsan",12,12.2 }, tem = { 0 };
	char arr1[100] = { 0 };
	sprintf(arr1, "%s %d %f", xy.name, xy.age, xy.score);
	sscanf(arr1, "%s %d %f", tem.name, &(tem.age), &(tem.score));
	printf("%s %d %f", tem.name,tem.age,tem.score);
	return 0;
}

sscanf是从arr1里面读取数据,然后放在了结构体里面,sprintf是输出到arr1里面,相较于前面的两组函数,这组函数是没有用到文件指针的,但是指针是用到了,由此可见指针的重要性。


5 文件的随机读写

文件的随机读写介绍三个函数 fseek ftell rewind:

int main()
{
	FILE* pf = fopen("data.txt", "r");
	assert(pf);
	for (int i = 0; i < 26; i++)
	{
		fputc('a' + i, pf);
	}
	char ch = fgetc(pf);
	printf("%c ", ch);//a

	ch = fgetc(pf);
	printf("%c ", ch);//b

	ch = fgetc(pf);
	printf("%c ", ch);//c

	ch = fgetc(pf);
	printf("%c ", ch);//d

	ch = fgetc(pf);
	printf("%c ", ch);//e

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

这段代码的意思就是文件里面有英文字母26个,使用fgetc函数一个一个读取,最后的打印结果应该是a b c d e,运行到d的时候文件指针,也就是光标,指向的是e,那么如果我们想要让文件指针回到最开始的位置,使得最后的打印结果还是a,就可以用到rewind:

int main()
{
	FILE* pf = fopen("data.txt", "r");
	assert(pf);
	for (int i = 0; i < 26; i++)
	{
		fputc('a' + i, pf);
	}
	char ch = fgetc(pf);
	printf("%c ", ch);//a

	ch = fgetc(pf);
	printf("%c ", ch);//b

	ch = fgetc(pf);
	printf("%c ", ch);//c

	ch = fgetc(pf);
	printf("%c ", ch);//d

	rewind(pf);

	ch = fgetc(pf);
	printf("%c ", ch);//e

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

rewind的参数就是一个文件指针,所以想要让文件指针回到起始位置用到一个rewind就行了。

那么如果我们想指定位置开始读取呢?这里用到的函数就是fseek函数,随机读取函数,可以

使文件指针指向最开始到结尾的任意位置:

它有3个参数,第一个参数是文件指针,第二个是偏移量,第三个是计算偏移量的起始位置,偏移量很好理解,光标指向第一个字符的时候偏移量就是0,往后一次偏移量增加1,那么第三个参数写的时候有三个选择,SEEK_SET,SEEK_CUR,SEEK_END,CUR就是当前位置的意思,SET就是起始位置的意思,END就是末尾的意思,所以移动光标的时候需要先确定好计算偏移量的起始位置,然后确定偏移量,从起始位置开始,往左计算偏移量就是负数,往右计算就是正数。

那么如果我懒我不想计算偏移量,我想直接知道现在的偏移量呢?只需要用ftell函数就是,参数就是文件指针,这个函数的返回值就是当前的偏移量。

如下:

int main()
{
	FILE* pf = fopen("data.txt", "r");
	assert(pf);
	for (int i = 0; i < 26; i++)
	{
		fputc('a' + i, pf);
	}
	char ch = fgetc(pf);
	printf("%c ", ch);//a

	ch = fgetc(pf);
	printf("%c ", ch);//b

	ch = fgetc(pf);
	printf("%c ", ch);//c

	ch = fgetc(pf);
	printf("%c ", ch);//d

	int num = ftell(pf);
	printf("%d ", num);

	//rewind(pf);
	fseek(pf, -2, SEEK_CUR);

	ch = fgetc(pf);
	printf("%c ", ch);//c

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

6 文件读取结束的判定

文件读取结束分为正常读取到了结尾和读到一半遇到错误了,那么我们如何判断文件是不是正常结束呢?这里用到的函数是feof,但是使用feof的前提是文件已经读取完了(不管是哪种结束),需要注意的是feof不能用来判断文件是不是读取结束了,这是前提,不要搞混淆了。

feof 的作⽤是:当⽂件读取结束的时候,判断是读取结束的原因是否是:遇到⽂件尾结束。

同理得ferror的作用是:当⽂件读取结束的时候,判断是读取结束的原因是否是:遇到错误结束。

当读取文本文件的时候,fgetc如果正常读取结束返回的是eof,fgets如果正常读取结束返回的是NULL,这也是它们的区别。

当读取二进制文件的时候,判断fread返回的值是否小于文件中的实际字符数,因为fread函数的返回值是读取到的个数。

文本文件代码示范:

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))
 puts("I/O error when reading");
 else if (feof(fp))
 puts("End of file reached successfully");
 fclose(fp);
}

二进制代码示范:

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);
 pf = NULL;
}

7 文件缓冲区

前面提到程序从计算机中读取数据的时候分为了好几个层次,其中包括看文件缓冲区,那么缓冲区的作用是是什么呢?
程序运行的时候内存会为每个正在使用的文件开辟缓冲区,读取数据的时候,数据就会往先往里面放,直到缓冲区装满了,才会一并送到磁盘中,相同的,如果程序需要输入数据,系统会将输入的数据放到输入缓冲区里面区,直到输入缓冲区满了,才会从磁盘输入到程序里面去。

那么缓冲区存在的意义是什么呢?

有人会说为什么不输出一个就给磁盘一个,实际上调用函数的时候,计算机底层也会被调用起来,所以看似工作的有程序,内存等,实际上还有计算机各个部分都是调用起来的,如果输出一个就传送一个出去,那其他部分的工作就是进行不下去,所以缓冲区存在的意义就是为了提高工作效率。

int main()
{
 FILE*pf = fopen("test.txt", "w");
 fputs("abcdef", pf);//先将代码放在输出缓冲区
 printf("睡眠10秒-已经写数据了,打开test.txt⽂件,发现⽂件没有内容\n");
 Sleep(10000);
 printf("刷新缓冲区\n");
 fflush(pf);//刷新缓冲区时,才将输出缓冲区的数据写到⽂件(磁盘)了
 printf("再睡眠10秒-此时,再次打开test.txt⽂件,⽂件有内容了\n");
 Sleep(10000);
 fclose(pf);
 //注:fclose在关闭⽂件的时候,也会刷新缓冲区
 pf = NULL;
 return 0;
}

我们先給文件一串字符串,然后让程序休眠10秒,也就是Sleep,Sleep需要引用到的头文件是windows,程序休眠的这10秒,我们打开文件就会发现abcdef是没有被写进去的,这个时候我们使用fflush刷新一下缓冲区,再去打开文件,就会发现abcdef写进去了,这个时候关闭文件,需要注意的是关闭文件的时候缓冲区也会被刷新,验证的方法就是把fclose提前,不使用fflush,这个时候也会发现文件过了10秒之后abcdef出现在了文件里面。

正因为缓冲区的存在,在进行关于文件类操作的时候,需要刷新缓冲区或者是关闭文件,不然很可能导致读写文件出现问题。


感谢阅读!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

(十)springboot实战——springboot3下的webflux项目mysql数据库事务处理

前言 WebFlux 是 Spring Framework 5.0 中引入的一种新型反应式编程模型&#xff0c;支持非阻塞 I/O&#xff0c;适用于高并发、高吞吐量的应用程序。在 WebFlux 应用程序中使用事务需要注意以下几点。使用 Reactive R2DBC&#xff1a;WebFlux 支持使用 Reactive R2DBC 访问关…

前端大厂面试题探索编辑部——第四期

目录 题目 单选题 题解 JavaScript的异步编程 Promise 异步函数async/await 关于Ajax 题目 这期只有一道题&#xff0c;我们来详细讲讲JavaScript的异步编程&#xff0c;当然&#xff0c;异步编程是许多编程语言都有的一种编程思想&#xff0c;我们在前端这个领域&#…

Python爬虫:XPath基本语法

XPath&#xff08;XML Path Language&#xff09;是一种用于在XML文档中定位元素的语言。它使用路径表达式来选择节点或节点集&#xff0c;类似于文件系统中的路径表达式。 不啰嗦&#xff0c;讲究使用&#xff0c;直接上案例。 导入 pip3 install lxmlfrom lxml import etr…

springboot中获取配置文件中属性值的几种方式

目录 第一章、使用Value注解第二章、使用PropertySource注解第三章、使用Configurationproperties注解第四章、使用Java Properties类第五章、使用Environment接口 友情提醒: 先看文章目录&#xff0c;大致了解文章知识点结构&#xff0c;点击文章目录可直接跳转到文章指定位置…

旋转花键磨损后如何修复?

旋转花键是机械传动中的一种&#xff0c;传递机械扭矩的&#xff0c;在轴的外表有纵向的键槽&#xff0c;套在轴上的旋转件也有对应的键槽&#xff0c;可保持跟轴同步旋转。在旋转的同时&#xff0c;有的还可以在轴上作纵向滑动&#xff0c;如变速箱换档齿轮等。 我们在使用某些…

VirtualBox安装Ubuntu22.04

目录 1、新建虚拟机 1.1、设置内存大小 1.2、创建虚拟硬盘 2、虚拟机设置 2.1、设置启动顺序​编辑 2.2、选择iso镜像文件 2.3、设置网络(桥接网卡) 3、启动 3.1、设置语言环境 3.2、系统更新安装(不更新) 3.3、选择键盘布局(默认即可) 3.4、选择安装类型 3.5、网…

项目实战:一个基于标准库的具备最值获取的万能容器实现

目录 写在前面 需求 分析 接口设计 项目实现 一些思考与总结 致谢 写在前面 刚刚介绍了变参模板和完美转发&#xff0c;现在换一换脑子做一个小的项目实战吧。博主最近学习的是标准库&#xff0c;总体来说&#xff0c;我认为标准库中的内容是很trivial的&#xff0c;重点…

STM32实时时钟(RTC)的配置和使用方法详解

实时时钟&#xff08;RTC&#xff09;是STM32系列微控制器上的一个重要模块&#xff0c;用于提供准确的时间和日期信息。在本文中&#xff0c;我们将详细介绍STM32实时时钟的配置和使用方法。 ✅作者简介&#xff1a;热爱科研的嵌入式开发者&#xff0c;修心和技术同步精进 ❤欢…

【C++】默认成员函数

与普通成员函数差距较大&#xff0c;形式对于我们比较陌生&#xff0c;但这是语法&#xff0c;是我们是必须要掌握的。 目录 类的默认成员函数&#xff1a;构造函数&#xff1a;概念&#xff1a;语法&#xff1a;特性&#xff1a; 析构函数&#xff1a;概念&#xff1a;语法&a…

Django模型(七)

一、聚合与分组查询 1.1、准备数据 class Cook(models.Model):"""厨师"""name = models.CharField(max_length=32,verbose_name=厨师名)level = models.IntegerField(verbose_name=厨艺等级)age = models.IntegerField(verbose_name=年龄)sect …

消息中间件之RocketMQ源码分析(三)

RocketMQ中的Consumer启动流程 RocketMQ客户端中有两个独立的消费者实现类分别为DefaultMQPullConsumer和DefaultMQPushConsumer&#xff0c; DefaultMQPullConsumer DefaultMQPullConsumer,该消费者使用时需要用户主动从Broker中Pull消息和消费消息&#xff0c;提交消费位点…

Springboot-SpringCloud学习

文章目录 web项目开发历史 SpringBootSpring以及Springboot是什么微服务第一个Springboot项目配置如何编写 yaml自动装配原理集成 web开发&#xff08;业务核心&#xff09;集成 数据库 Druid分布式开发&#xff1a;Dubbo&#xff08;RPC&#xff09; zookeeperswagger&#x…

掌握使用 React 和 Ant Design 的个人博客艺术之美

文章目录 前言在React的海洋中起航安装 Create React App安装Ant Design 打造个性化的博客风格通过路由实现多页面美化与样式定制部署与分享总结 前言 在当今数字时代&#xff0c;个人博客成为表达观点、分享经验和展示技能的独特平台。在这个互联网浪潮中&#xff0c;选择使用…

新火种AI|脑洞照进现实!马斯克正式官宣,已将芯片连入大脑...

作者&#xff1a;小岩 编辑&#xff1a;彩云 2024年1月30日&#xff0c;马斯克在社交媒体上宣布&#xff0c;他的公司Neuralink已经完成了首例人类大脑芯片植入手术&#xff0c;并且目前手术恢复状况良好。这一突破性进展意味着人类距离实现大脑与电脑的直接连接更近了一步。…

【mysql】InnoDB引擎的索引

目录 1、B树索引 1.1 二叉树 1.1.1 二分查找&#xff08;对半查找&#xff09; 1.1.2 树&#xff08;Tree&#xff09; 1.1.2.1 树的定义 1.1.2.2 树的特点 1.1.2.3 二叉树 1.1.2.4 二叉查找&#xff08;搜索&#xff09;树 1.2 B树 1.2.1 聚簇索引&#xff08;clust…

AI-数学-高中-14-函数零点存在定理和运用

原作者视频&#xff1a;【函数综合】【考点精华】1零点存在性定理的运用&#xff08;基础&#xff09;_哔哩哔哩_bilibili 1.定义&#xff1a; 2.零点存在定义&#xff1a; 2.函数零点与图像焦点的转化 零点如果不好求&#xff0c;将函数化成两个函数再画图&#xff0c;看函数…

防抖和节流?有什么区别?如何实现?

#一、是什么 本质上是优化高频率执行代码的一种手段 如&#xff1a;浏览器的 resize、scroll、keypress、mousemove 等事件在触发时&#xff0c;会不断地调用绑定在事件上的回调函数&#xff0c;极大地浪费资源&#xff0c;降低前端性能 为了优化体验&#xff0c;需要对这类…

计算机网络-物理层传输介质(导向传输介质-双绞线 同轴电缆 光纤和非导向性传输介质-无线波 微波 红外线 激光)

文章目录 传输介质及分类导向传输介质-双绞线导向传输介质-同轴电缆导向传输介质-光纤非导向性传输介质小结 传输介质及分类 物理层规定电气特性&#xff1a;规定电气信号对应的数据 导向传输介质-双绞线 双绞线的主要作用是传输数据和语音信息。它通过将两根导线以特定的方…

python爬虫2

1.table 是表格&#xff0c;tr是行&#xff0c;td是列 ul li是无序列标签用的较多&#xff0c;ol li是有序列标签 最基本的结构 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><title> Title </title>…

【JavaEE】UDP协议与TCP协议

作者主页&#xff1a;paper jie_博客 本文作者&#xff1a;大家好&#xff0c;我是paper jie&#xff0c;感谢你阅读本文&#xff0c;欢迎一建三连哦。 本文于《JavaEE》专栏&#xff0c;本专栏是针对于大学生&#xff0c;编程小白精心打造的。笔者用重金(时间和精力)打造&…