C——文件操作

1.前言

为什么要使用文件呢?

文件是储存在电脑的磁盘中的,如果没有文件,我们写程序的数据就会存储在电脑的内存中,程序退出,操作系统就会收回内存,数据就丢失了等再次运行程序的时候,是看不到上次的数据的,如果想要将数据持久化的保存,我们就可以使用文件。

2.什么是文件?

在磁盘上存储的文件就是文件。磁盘就是电脑上的硬盘存储,而文件就是电脑中的C盘、D盘等等上的文件。但是在程序操作中,我们一般谈的文件有两种:程序文件、数据文件(从文件的功能来分类的)。

2.1程序文件

程序文件包括源文件(.c为后缀的文件),目标文件(.obj为后缀的文件),可执行程序(.exe为后缀的文件)。

2.2数据文件

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

我们在此讨论的是数据文件。

在以前的学习中所处理的数据的输入输出都是以终端为对象的,即从终端键盘上获取数据,将数据的运行结果打印到终端屏幕上。

而我们有时候需要将数据输出到磁盘中,或者从磁盘中得到我们需要的数据然后在内存上进行使用。这里我们就是对数据文件进行操作。

2.3文件名

文件要有一个唯一的标识符,以便用户识别和引用。

文件名包含三部分:文件路径+文件名主干+文件后缀。

 为了方便起见,文件标识常被称为文件名。我们将下面的就叫做文件名。

 3.二进制文件和文本文件

根据数据的组织形式,数据文件被分为二进制文件和文本文件。

数据在内存中以二进制的形式存储,如果不加任何转化直接存入文件中,就是二进制文件。

如果要求外存时以ASCII码值的形式存储,则需要在存储前进行转化。以ASCII字符的形式存储的文件就是文本文件。

如果用通俗的语言来说,文本文件是我们用眼睛能够看懂的,而二进制文件我们是看不懂的。

下面我来写段代码给大家看一下文本文件和二进制文件的区别。

 我利用该代码创建了一个test1.txt的文本文件和test2.txt的二进制文件。我给两个文件内存的东西是一样的数组,我们现在来看一下这两个文件的内容。

而当我们打开test2.txt时,系统就会提示该文件是二进制文件。

而当我们以记事本的形式打开的时候发现里面是一些我们看不懂的东西。这就是二进制文本与文本文件最明显的区别。 我们利用VS里面的二进制编辑器来打开该文件看看。

打开后为:

 我们刚才给该文件存的是1,2,3,4,5这5个整数,而在该文件中确实是以二进制的形式存储了这5个数。

4.文件的打开和关闭

4.1流和标准流

4.1.1流

我们程序的数据需要输出到各种外部设备,也需要从外部设备获取数据,不同的外部设备的输入输出操作各不相同,为了方便程序员对各种设备进行方便的操作,我们抽象出了流的概念,我们可以把流想象成流淌着字符的河。C程序针对文件、画面、键盘等的数据输入输出操作都是通过流操作的。⼀般情况下,我们要想向流里写数据,或者从流中读取数据,都是要打开流,然后操作。

4.1.2标准流

那为什么我们从键盘输⼊数据,向屏幕上输出数据,并没有打开流呢? 那是因为C语言程序在启动的时候,默认打开了3个流:

  1. stdin-标准输入流,在大多数的环境中从键盘输入,scanf函数就是从标准输入流中读取数据。
  2. stdout-标准输出流,大多数的环境中输出至显示器界面,printf函数就是将信息输出到标准输出流中。
  3. stderr-标准错误流,大多数环境中输出到显示器界面。 

 这是默认打开了这三个流,我们使用scanf、printf等函数就可以·1直接进行输入输出操作。stdin、stdou、stderr这三个流的类型是FILE*,通常被称为文件指针。在C语言中,就是通过FILE*的文件指针来维护流的各种操作的。

而在我个人看来,流其实就是C程序所面对的一个对象,window终端可以被看作一个流,对其操作就是利用键盘获取数据,利用屏幕打印数据。而对文件来说,我们可以将文件看作一个文件流,C程序通过各种函数对该文件进行写数据和读数据等操作。

4.2文件指针

我们对文件的各种操作都要依靠于文件指针。

当我们打开一个文件时,此时系统会内存生成内存空间作为文件信息区,用来存放文件的相关信息。这些信息是保存在一个结构体变量中的。该结构体变量由系统进行声明,取名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;

不同的C语言编译器中FILE类型包含的内容是不完全相同的,但是大同小异。

每当我们打开一个文件时,程序就会自动创建一个FILE类型的变量,并自动填充里面的内容,使用者不必关心里面的细节。

我们一般都是通过一个FILE*类型的指针来维护这个FILE结构体变量,这样使用起来更加方便。

FILE* pf;//文件指针

定义pf为一个指向FILE结构体变量的结构体指针变量。我们可以使pf指向某个文件的文件信息区的任何一个位置。通过该文件信息区就能访问到该文件。也就是说,利用文件指针可以间接找到我们需要的文件。

4.3文件的打开和关闭

文件在读写之前应该先打开文件,读写完毕后关闭文件。打开文件的时候会返回一个FILE*类型的指针。ANSI 规定使用fopen打开文件,使用fclose来关闭文件。

const char *filename:需要打开的文件的文件名

const char * mode:打开文件的方式

打开文件的方式有:

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

我们现在利用上面的知识来打开一个文件。

#include <stdio.h>int main()
{//打开文件FILE* pf = fopen("demo.txt", "r");//我们要以读的形式打开demo.txt这个文件return 0;
}

 但是我们一定可以打开成功么?我们来看看fopen的返回值

 如果成功打开,则返回一个FILE*类型的指针,打开失败则返回空指针。为了避免对空指针的解引用操作,我们在使用该文件指针之前,最好对其进行判断,看其是否为空。如果打开失败,我们就没必要在运行该程序了,直接终止程序。

int main()
{//打开文件FILE* pf = fopen("demo.txt", "r");//我们要以读的形式打开demo.txt这个文件if (pf == NULL){perror("fopen");return -1;}return 0;
}

 我们下来运行该程序看看结果如何?

打印了错误信息,说明打开失败了。这是为什么呢?我们以读的形式打开该文件,我们知道以读的形式打开文件时,如果文件不存在会报错。那么就说明我们当前目录下没有demo.txt这个文件。

我们打开该目录发现确实没有该文件,所以以读的形式打开时就会出错。

而我们先前已经知道以写的形式,如果文件存在则正常打开,如果文件不存在,则会创建一个该文件名的文件。

int main()
{//打开文件FILE* pf = fopen("demo.txt", "w");//我们要以写的形式打开demo.txt这个文件if (pf == NULL){perror("fopen");return -1;}return 0;
}

 我们当前目录下并没有该文件,我们看是否可以生成一个以demo.txt为文件名的文件。

运行成功了,并没有报错。因为我们并没有任何打印语句,所以黑框框上面没有打印信息。我们再看下图,的确在当前路径下面生成了一个新的文件,文件名与我们写的相同。

 通过上述操作我们就成功打开了一个文件,然后我们就可以对文件进行操作。等我们操作完后,文件就这么放这么?当然不行。操作系统打开文件的数量是有上限的。我们在对文件完成操作后应该进行关闭文件的操作。这就要用到另一个函数——fclose。

我们就以上面打开的文件,再对其进行关闭操作。fclose的参数就是一个文件指针,打开文件会返回一个文件指针,我们只需把文件指针传给fclose即可。

int main()
{//打开文件FILE* pf = fopen("demo.txt", "w");//我们要以写的形式打开demo.txt这个文件if (pf == NULL){perror("fopen");return -1;}//对文件进行操作//....//关闭文件fclose(pf);return 0;
}

那这样就可以了嘛?我们只是关闭了文件,那就说明文件信息区就被关闭了,文件指针pf就没有指向的地址了,那它就有可能成为野指针。为了避免这种情况发生,我们在关闭文件后,最好将文件指针pf置为空,这样就规避了野指针的风险。

	//关闭文件fclose(pf);pf = NULL;

5.文件的顺序读写

5.1顺序读写函数介绍

函数名功能

适用于

fgetc字符输入函数所有输入流
fputc字符输出函数所有输出流
fgets文本行输入函数所有输入流
fputs文本行输出函数所有输出流
fscanf格式化输入函数所有输入流
fprintf格式化输出函数所有输出流
fread二进制输入文件
fwrite二进制输出文件

我现在依次简单介绍这几个函数。

5.1.1字符输入函数

fputc

该函数的功能是写一个字符到流中。参数character就是我们要写进去的字符,stream就是我们要写进去的流,其实就是文件流,这里我们把对应文件的文件指针传过去即可。

该函数是给一个文件写字符,所以我们打开文件应该以读的形式。

//fputc
#include <stdio.h>int main()
{//打开文件FILE* pf = fopen("demo.txt", "w");//我们要以写的形式打开demo.txt这个文件if (pf == NULL){perror("fopen");return -1;}//将一个字符写入该文件中fputc('a', pf);//关闭文件fclose(pf);pf = NULL;return 0;
}

我们看到,确实将字符'a'写进了该文件。那现在,我们将26个字母全都写进该文件中。

	//将26个字母全都写入该文件中char ch = 'a';while (ch<='z'){fputc(ch, pf);ch++;}

我们也成功将26个字母写进了文件,我们看到,第一次写进去的a已经不见了,所以以写的形式打开文件,每次写之前都会将文件清空再往里面写。

fgetc

fgetc的功能是从文件流中读取一个字符,参数就是文件指针。 我们现在将上面给文件写进去的字符取出来,打印在屏幕上。我们现在是要从文件读取字符,所以我们要以读的形式打开文件。

//fgetc
#include <stdio.h>int main()
{//打开文件FILE* pf = fopen("demo.txt", "r");//我们要以读的形式打开demo.txt这个文件if (pf == NULL){perror("fopen");return -1;}//将文件中的26个字母取出来int ch = 0;while ((ch = fgetc(pf)) != EOF){printf("%c", ch);}//关闭文件fclose(pf);pf = NULL;return 0;
}

注意fgetc函数一次只能读取一个字符,读到文件末尾或者读取失败会返回EOF。

fputs

该函数的功能是将一个字符串写入流中。const char* str:就是字符串的首地址,FILE* stream就是指向流的指针。

//fputs
#include <stdio.h>int main()
{char arr[] = "abcdefg";//打开文件FILE * pf = fopen("test.txt", "w");if (pf == NULL){perror("fopen");return -1;}//将字符串写入文件流中fputs(arr, pf);//关闭文件fclose(pf);pf = NULL;return 0;
}

运行程序,我们就可以将arr字符数组的内容写入文件中。 

fgets 

该函数的功能是从文件流中得到一个字符串。

char *str:用来存储从文件中获得的字符串

int num:复制到str的最大字符数

FILE *stream:文件指针 

我们事先在该文件下存放了这个字符串,我们利用fgets取出他,后将他打印在屏幕上。 

我们还需要注意的是,fgets会将\0也放入字符数组中。

我们看,它会将字符串复制过去后在追加一个\0在末尾。该函数会优先考虑\0,如果最大复制数为1,那么他就会把\0放到数组中。所以实际上你的最大复制数是num-1。

换行符会使fgets停止读取。 我们给该文件中放入三行信息,是否能一次性打印呢?

尽管我们的最大字符数已经大于文件所有的字符数,但是依旧不能全部打印出来。这是因为fgets遇到换行符会自动停止读取。所以为了将这三行信息打印出来,我们可以分三次打印。 

fprintf

fprintf与上面的区别在于,它可以将格式化的字符写入文件中。

//fprintf
#include <stdio.h>struct S
{char name[20];int age;float weight;
};int main()
{struct S s = { "zhangsan",18,65.5 };//打开文件FILE* pf = fopen("test.txt", "w");if (pf == NULL){perror("fopen");return -1;}//将结构体中的格式化的数据写入文件中fprintf(pf, "%s %d %f", s.name, s.age, s.weight);//关闭文件fclose(pf);pf = NULL;return 0;
}

程序运行后,就将该格式化的字符写入文件中了

fscanf

 fscanf的用法刚好和fprintf相反,它是从文件中读取格式化的数据。

	//将文件中的格式化数据读取后存放在结构体变量中fscanf(pf, "%s %d %f", s.name, &(s.age), &(s.weight));//读取后将内容打印在屏幕上printf("%s %d %f", s.name, s.age, s.weight);

因为我们要从文件中读取数据,所以我们要以读的形式打开文件。因为我们是要取出数据放入变量中,所以我们要用地址来接收。 

fread和fwrite 

这两个函数是以二进制的形式将数据写入文件流中或者从文件流中读取。

const void * ptr:存放数据的数组

size_t size:数组中每个数据的大小

size_t:数组中元素的个数

FILE * stream:文件流指针


//fwrite
#include <stdio.h>int main()
{int arr[] = { 1,2,3,4,5 };//打开文件FILE* pf = fopen("test.txt", "w");if (pf == NULL){perror("fopen");return -1;}//将数组arr的数据以二进制的形式写入文件中fwrite(arr,sizeof(int),5,pf);//关闭文件fclose(pf);pf = NULL;return 0;
}

 程序运行结束后,该数组中的内容就以二进制的形式存放进了该文件中。而数据以二进制的形式存放在文件中我们是看不懂的。

存放后,我们在利用fread函数,以二进制的形式将上述数据读取出来并打印在屏幕上。 我们这下利用fread函数来实现。

fread函数的功能就是从文件中读取数据块。

void * ptr:存放数据块的数组

size_t size:每个数据的大小

size_t count:有多少个数据

FILE * stream:文件流指针 

	//将文件中储存的5个整形读取出来存放在arr中,并打印在屏幕上fread(arr, sizeof(int), 5, pf);int i = 0;for (i = 0; i < 5; i++){printf("%d ", arr[i]);}

 存放数据的数据必须足够大。我们要从文件中读取数据,所以要采用读的形式打开文件。

5.2对比一组函数 

scanf/fscanf/sscanf

printf/fprintf/sprintf

 5.2.1scanf/fscanf/sscanf

scanf和fscanf我们已经了解,现在我们了解一下sscanf这个函数。

//sscanf
#include <stdio.h>struct S
{char name[20];int age;float weight;
};
int main()
{struct S s = { 0 };char str[20] = "zhagnsan 18 65.5";//从字符串中读取格式化的数据放入结构体变量中sscanf(str, "%s %d %f", s.name, &(s.age), &(s.weight));//打印结构体变量printf("%s %d %f",s.name,s.age,s.weight);return 0;
}

我们使用该函数后,再利用printf格式化打印结构体变量可以成功打印。说明sscanf确实将字符串中的内容转化成了格式化的数据。

5.2.2printf/fprintf/sprintf

我们来看一下sprintf函数: 

//sprintf
#include <stdio.h>struct S
{char name[20];int age;float weight;
};
int main()
{struct S s = { "zhagnsan", 18, 65.5 };char str[30] = { 0 };//从结构体变量中读取格式化数据转化成字符串存放在str中sprintf(str, "%s %d %f", s.name, s.age, s.weight);//打印字符串printf(str);return 0;
}

使用完该函数后,我们成功将格式化的数据存放进了字符串中,并通过打印字符串显示出了刚才的数据。 

6.文件的随机读写

我们利用上面的函数,只能按照顺序从前到后的读取数据或者写入数据。如果我们想指哪打哪可不可以呢?

当然是可以的。下面来介绍随机读写可能用到的几个函数。

6.1fseek

fseek的功能就是使文件指针指向以orign为参考位置偏移量为offset的位置处。 

FILE * stream:文件指针

long int offset:偏移量

int origin:参考位置

对于参考位置来说,有三种位置: 

第一个指的是文件起始位置,第二个指的是文件指针的当前位置,第三个指的是文件末尾。

 如果我们直接使用fgetc读取的话,只会按照顺序一个一个读取,如果我们想取出a后,然后直接取出f呢?我们就可以利用fseek函数实现。

//fseek
#include <stdio.h>int main()
{//以读的形式打开文件FILE* pf = fopen("test.txt", "r");if (pf == NULL){perror("fopen");return -1;}//文件中已经存放了abcdefghi这个字符串,如果我们直接使用fgetc就会拿到aint ch = fgetc(pf);printf("%c\n", ch);//我们以起始位置为参考,只需偏移5个位置,就可以拿到ffseek(pf, 5, SEEK_SET);//此时,pf已经指向f了,我们现在在利用fgetc读取一个字符,读到的就是fch = fgetc(pf);printf("%c\n", ch);//关闭文件fclose(pf);pf = NULL;return 0;
}

6.2ftell 

ftell的功能是返回当前文件指针的当前位置。

6.3rewind

该函数的功能就是使文件指针重新指向文件的起始位置。

//rewind
#include <stdio.h>int main()
{//以读的形式打开文件FILE* pf = fopen("test.txt", "r");if (pf == NULL){perror("fopen");return -1;}//文件事先已经写入了abcdefghi//我们以起始位置为参考,只需偏移5个位置,就可以拿到ffseek(pf, 5, SEEK_SET);int ch = fgetc(pf);printf("%c\n", ch);//我们在使用rewind函数,使文件指针重新指向起始位置rewind(pf);printf("%c\n", fgetc(pf));//现在在取出一个字符的话,就是a//关闭文件fclose(pf);pf = NULL;return 0;
}

7.文件读取结束的判定 

7.1文本结束判定

文本文件读取是否结束,判断返回值是否为EOF(fgetc),或者NULL(fgets)

例如:

1.fgetc判断是否为EOF

2.fgets判断返回值是否为NULL

二进制文件的读取结束判断,判断返回值是否小于实际要读的个数

例如:

fread判断返回值是否小于实际要读的个数。

 7.2feof的使用

该函数的作用使判断文件结束是否是因为遇到了文件末尾。如果确实是遇到文件末尾而停止,则返回非0数,如果是遇到错误而停止,则返回0。

7.3ferror的使用

该函数的作用是文件读取结束后,判断是否是因为遇到错误而停止的。 如果确实是因为遇到错误而停止,则返回非0数,如果是正常结束的,则返回0。

8.文件缓冲区

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

 这⾥可以得出⼀个结论:

因为有缓冲区的存在,C语言在操作文件的时候,需要做刷新缓冲区或者在文件操作结束的时候关闭文件。

如果不做,可能导致读写文件的问题。

完!

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

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

相关文章

【春秋云镜】CVE-2023-43291 emlog SQL注入

靶场介绍 emlog是一款轻量级博客及CMS建站系统&#xff0c;在emlog pro v.2.1.15及更早版本中的不受信任数据反序列化允许远程攻击者通过cache.php组件执行SQL语句。 不感兴趣的可以直接拉到最后面&#xff0c;直接获取flag 备注&#xff1a;没有通过sql注入获取到flag&…

汇编语言——将DX,AX组成的32位数逻辑左移3位

data segment data ends stack segment stacktop label worddw 100 dup (?) stack ends code segmentassume cs:code,ds:data,ss:stack main proc farmov ax,datamov ds,axmov ax,stackmov ss,axlea sp,top;0000 0001 1100 1010 | 0000 0010 0001 1111;逻辑左移三位后&#xf…

基于SpringBoot框架的智慧食堂

采用技术 基于SpringBoot框架实现的web的智慧社区系统的设计与实现~ 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBootMyBatis 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 页面展示效果 系统功能 系统首页 用户注册页面 菜品信息页面 …

Android 性能优化(七):APK安装包体积优化

包体积优化重要性 移动 App 特别关注投放转化率指标&#xff0c;而 App 包体积是影响用户新增的重要因素&#xff0c;而 App 的包体积又是影响投放转化率的重要因素。 Google 2016 年公布的研究报告显示&#xff0c;包体积每上升 6MB 就会带来下载转化率降低 1%&#xff0c; …

直方图与核密度估计

技术背景 直方图是一种经常被用于统计的图形表达形式&#xff0c;简单来说它的功能就是用一系列的样本数据&#xff0c;去分析样本的分布规律。而直方图跟核密度估计(Kernel Density Estimation&#xff0c;KDE)方法的主要差别在于&#xff0c;直方图得到的是一个离散化的统计分…

【全开源】多功能完美运营版商城 虚拟商品全功能商城 全能商城小程序 智慧商城系统 全品类百货商城

内容目录 一、详细介绍二、效果展示1.部分代码2.效果图展示 三、学习资料下载 一、详细介绍 完美运营版商城/拼团/团购/秒杀/积分/砍价/实物商品/虚拟商品等全功能商城 干干净净 没有一丝多余收据 还没过手其他站 还没乱七八走的广告和后门 后台可以自由拖曳修改前端UI页面 …

Aigtek功率放大器的使用方法有哪些

功率放大器是一种将小信号放大为大信号的电子设备&#xff0c;广泛应用于无线通信、音频系统、雷达等领域。在使用功率放大器时&#xff0c;需要注意以下几个方面&#xff1a; 电源供应&#xff1a;功率放大器需要提供稳定的电源供应以保证正常工作。通常情况下&#xff0c;功率…

正式发布的Spring AI,能让Java喝上AI赛道的汤吗

作者:鱼仔 博客首页: https://codeease.top 公众号:Java鱼仔 前言 最近几年AI发展实在太快了&#xff0c;仿佛只要半年没关注&#xff0c;一个新的大模型所产生的效果就能超越你的想象。Java在AI这条路上一直没什么好的发展&#xff0c;不过Spring最近出来了一个新的模块叫做S…

[Linux][进程间通信][一][匿名管道][命名管道]详细解读

目录 0.进程间通信&#xff1f;1.进程间通信目的2.进程间通信分类3.进程间通信的本质理解 1.什么是管道&#xff1f;2.匿名管道1.认识函数2.如何让不同的进程&#xff0c;看到同一份资源&#xff1f;3.用fork来共享管道原理4.站在文件描述符角度 -- 深刻理解管道5.站在内核角度…

目标检测——食品饮料数据集

一、重要性及意义 对食品和饮料进行目标检测的重要性和意义体现在多个方面&#xff1a; 商业应用与市场分析&#xff1a;目标检测技术在食品和饮料行业有着广泛的应用前景。通过对超市货架、餐馆菜单或广告海报中的食品和饮料进行自动识别和计数&#xff0c;商家可以获取关于产…

【微服务】spring状态机模式使用详解

一、前言 在很多系统中,通常会涉及到某个业务需要进行各种状态的切换操作,例如在审批流程场景下,某个审批的向下流转需要依赖于上一个状态的结束,再比如电商购物场景中,一个订单的生命周期往往伴随着不同的状态,比如待支付,支付完成,已发货等等,状态的存在,让一个业…

登录解析(后端)

调试登录接口 进入实现类可以有 验证码校验 登录前置校验 用户验证 验证码校验 通过uuid获取redis 中存储的验证码信息&#xff0c;获取后对用户填写的验证码数据进行校验比对 用户验证 1.进入控制器的 /login 方法 2.进入security账号鉴权功能&#xff0c;经过jar内的流…

HTML:Form表单控件主要标签及属性。name属性,value属性,id属性详解。表单内容的传递流程,get和post数据传递样式。表单数据传递实例

form表单 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title> </head> &…

c语言中什么是冒泡排序,冒泡排序的计算

在c语言中&#xff0c;冒泡排序的解释是&#xff0c;将被排序的记录数组arr[1..n]垂直排列&#xff0c;每个记录arr看作是重量为一个arr气泡。根据轻气泡不能在重气泡之下的原则&#xff0c;从下往上扫描数组arr&#xff0c;凡扫描到违反该原则的轻气泡&#xff0c;就使其向上飘…

算法练习第19天|222.完全二叉树的节点个数

222.完全二叉树的节点个数 222. 完全二叉树的节点个数 - 力扣&#xff08;LeetCode&#xff09;https://leetcode.cn/problems/count-complete-tree-nodes/description/ 题目描述&#xff1a; 给你一棵 完全二叉树 的根节点 root &#xff0c;求出该树的节点个数。题目数据保…

振动信号幅值成分分析手段

提示&#xff1a;振动信号幅值成分分析手段 文章目录 一、特征值分析二、概率密度分析2.1、原理2.2、代码2.3、结果分析 三、总结&#xff08;自己的思想&#xff09; 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、特征值分析 均值和平均幅值可以…

【缓存常见问题】

在使用缓存时特别是在高并发场景下会遇到很多问题&#xff0c;常用的问题有缓存穿透、缓存击穿、缓存雪崩以及缓存一致性问题。 1、缓存穿透 首先&#xff0c;什么是缓存穿透呢&#xff1f; 缓存穿透是指请求一个不存在的数据&#xff0c;缓存层和数据库层都没有这个数据&…

虚拟天空解决方案,创造出令人惊叹的换天效果

在汽车视频领域&#xff0c;如何打破传统拍摄限制&#xff0c;呈现出更具创意和想象力的画面&#xff0c;成为众多企业和创作者追求的目标。美摄科技作为业界领先的视频技术提供商&#xff0c;凭借其强大的AI技术和三维渲染引擎&#xff0c;推出了全新的虚拟天空解决方案&#…

集成电路测试学习

集成电路&#xff08;Integrated Circuit&#xff0c;IC&#xff09;整个设计流程包括&#xff1a;电路设计、晶圆制造、晶圆测试、IC封装、封装后测试。 IC测试目的&#xff1a;一、确认芯片是否满足产品手册上定义的规范&#xff1b;二、通过测试测量&#xff0c;确认芯片可以…

李国武:QFD是如何将顾客需求转换为产品技术要求的?

如何将顾客的多样化需求精准地转化为产品的技术要求&#xff0c;成为企业赢得市场、提升竞争力的关键。质量功能展开&#xff08;Quality Function Deployment&#xff0c;简称QFD&#xff09;作为一种先进的质量管理工具&#xff0c;正是实现这一转换的有效桥梁。具体如天行健…