【C语言进阶】文件的顺序读写、随机读写、文本文件和二进制文件、文件读取结束的判定以及文件缓冲区相关知识

news2024/11/19 2:47:32

在这里插入图片描述

​📝个人主页:@Sherry的成长之路
🏠学习社区:Sherry的成长之路(个人社区)
📖专栏链接:C语言进阶
🎯长路漫漫浩浩,万事皆有期待

文章目录

  • 1.文件操作
    • 1.1 概述:
      • 1.1.1 为什么使用文件:
      • 1.1.2 什么是文件:
        • ①.程序文件:
        • ②.数据文件:
        • ③.文件名:
  • 2. 文件顺序读写:
    • 2.1 文件的打开和关闭:
      • ①.文件指针:
      • ②.文件的打开与关闭:
      • ③.文件打开模式:
    • 2.2.文件的顺序读写:
  • 3. 文件随机读写:
    • 3.1 fseek 函数:
    • 3.2 ftell 函数:
    • 3.3 rewind 函数:
  • 4. 文本文件与二进制文件:
  • 5. 文件读取结束的判定:
    • 5.1 错误使用 feof 函数:
    • 5.2 判断文件读取结束:
  • 6. 文件缓冲区:
  • 7.总结:

1.文件操作

1.1 概述:

我们进行的所有操作都是在计算机内存中进行的,并且我们所操作的数据也是存放在计算机内存中的,一旦我们退出了程序,内存空间就会被释放并回收,而这个过程中我们所操作的所有的数据也将不复存在。如此,我们无法将数据真正保留下来,只能在每次运行程序时重新进行输入,重新录入信息,使用起来极为不便。

1.1.1 为什么使用文件:

我们希望将数据保留在本地,只有当我们进行删除操作时,才将对应的数据删除掉,即尝试实现数据的持久化。而我们实现数据持久化的方式一般有两种:使用数据库将数据存放至本地磁盘中。
目前还没有接触到数据库的知识,于是我们便通过学习文件操作,来将我们的数据存放至我们计算机的本地硬盘中,从而实现数据的持久化。

1.1.2 什么是文件:

我们通常所说的文件,一般是指存放在我们计算机本地硬盘上的文件。但是在我们的程序设计中(根据文件功能分类),指的是程序文件数据文件两种文件。

①.程序文件:

程序文件主要包括源程序文件、目标文件和可执行程序文件。

源程序文件(后缀为 .c)
目标文件( Windows 环境下后缀为 .obj)
可执行程序文件( Windows 环境下后缀为 .exe)

②.数据文件:

数据文件的内容不一定是程序,而是程序运行过程中所进行读写的数据,比如程序运行中需要从中读取的数据,或者程序运行完毕所输出的文件。
今天所讨论的,正是数据文件的相关操作
在前面所有内容的学习中,我们所有的输入输出,其操作对象都是终端,均为从键盘读取输入内容,并将处理结果输出致我们的计算据显示器上进行反馈。而今天我们的目的则是将数据信息输入至我们的本地磁盘上,当我们想要对数据进行操作时,便从本地硬盘进行读取。

③.文件名:

文件和我们人类有自己的名字一样,也需要有一个文件标识符,文件名的存在就是为了便于我们进行识别和引用。
而一个文件的文件名由三部分组成:文件路径 + 文件名主干 + 文件后缀

以文件名“ c:\code\test.txt ”为例:
文件路径为“ c:\code\ ”,表示文件存放在硬盘 C 盘下的 code 文件夹内。
文件名主干为“ test ”,表示该文件的文件名为 test。
文件后缀为“ .txt ”,表示该文件的文件类型为文本文件。

2. 文件顺序读写:

2.1 文件的打开和关闭:

我们在使用或操作我们的文件之前,首先需要在我们的程序中及将其打开

①.文件指针:

首先需要了解一下文件指针这个概念,这是因为不光是文件的打开与关闭,包括后面我们在对我们的文件进行操作时,也都是通过文件指针实现的。
在缓冲文件系统中,最关键的一个概念就是“ 文件类型指针 ”,即我们通常所说的“ 文件指针 ”。并且我们要知道,我们使用的每一个文件都在内存中开辟了相应的文件信息区,用于存放该文件的相关信息,并且这些信息都保存在一个结构体变量中。
并且这样的结构体类型是有系统声明的,取名为 FILE
例如在 Visual Studio 的头文件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* p;
//定义一个文件指针p

像这样,我们就能创建出一个文件指针,而接下来就可以使这个文件指针 p 指向某个文件信息区(FILE 类型的结构体变量),并通过该文件信息区中所保存的信息来访问本地硬盘内的文件了。通过使用文件指针就可以找到与其相关联的文件了。

②.文件的打开与关闭:

应在读写文件之前打开文件,并在文件读写结束后关闭文件。同时ANSI C规定,使用 fopen 函数(file open)来打开文件,用 fclose 函数(file open)来关闭文件。

什么是ANSI C、ISO C、C89、C90标准?
随着C语言使用得越来越广泛,出现了许多新问题,人们日益强烈地要求对C语言进行标准化。1983年,美国国家标准协会(ANSI)组成了一个委员会,X3J11,为了创立C的一套标准。经过漫长而艰苦的过程,该标准于1989年完成,这个版本的语言经常被称作ANSI C,或有时称为C89(为了区别C99)在1990年,ANSI C标准(带有一些小改动)被美国国家标准协会(ANSI)采纳为ISO/IEC 9899:1990。这个版本有时候称为C90或者ISO C。综上,ANSI C、ISO C、C89、C90其实是同一种标准。

open 函数的使用方式为:

FILE* p = fopen(const char* filename, const char* mod);

1.其中“ const char* filename ”指文件名(是字符串,文件名即文件标识符)。
2.其中“ const char* mod ”指文件打开模式(也是字符串,后面会列出)

int main()
{
	//打开文件:
	FILE* p = fopen("test.txt", "r");
	//以"r",即只读模式打开文件c:\code\test.txt
    //默认路径为.c文件同目录下
	if (p == NULL)
	//判断文件打开是否成功
	{
		perror("FILEOPEN");
		//打开失败打印错误原因并退出
		return 1;
	}
    printf("success\n");
	return 0;
}

fclose 函数的使用方式为:

 fopen(FILE* strname);

“ FILE* strname ”指的是指向期望关闭文件的文件指针。
因为我们在打开文件时没有特意注明路径,则默认路径为 .c 文件的同目录下。为了验证我们代码的正确性,我们在该目录下创建“ test.c ”文件用于代码测试:
在这里插入图片描述

int main()
{
	//打开文件:
	FILE* p = fopen("test.txt", "r");
	//以"r",即只读模式打开文件c:\code\test.txt
	if (p == NULL)
	//判断文件打开是否成功
	{
		perror("FILEOPEN");
		//打开失败打印错误原因并退出
		return 1;
	}
	printf("open success\n");
	//验证文件是否成功打开
	fclose(p);
	p = NULL;
	if (p == NULL)
	{
		printf("close success\n");
		//验证文件是否成功关闭
	}
	return 0;
}

在这里插入图片描述

③.文件打开模式:

请添加图片描述

2.2.文件的顺序读写:

请添加图片描述
这其中较为常用的就是 fputc 函数与 fgetc 函数,我们一般就通过这两个函数来实现对文件内容的顺序读写。
这两个函数的使用方式为:

fputc(const char charname, FILE* strname);
fget(FILE* strname);

首先文本文件 test.txt 中的内容为空,没有内容
接下来我们使用“ 写 ”模式打开该文件,并在判断非空后使用 fputc 函数来进行顺序写入:

int main()
{
    FILE* p = fopen("test.txt", "w");
    //文件打开模式为“写”
    if (p == NULL)
    {
    	perror("FILEOPEN");
	    return 1;
    }
    char ch = 'a';
    for (ch = 'a'; ch <= 'z'; ch++)
    {
    	fputc(ch, p);
        //使用 fputc 函数顺序写入小写字符a~z
    }
    fclose(p);
    p = NULL;
    return 0;
}

我们等待程序编译运行并完成数据写入后关闭程序,这时我们来到本地文件中查看硬盘中本地文件的数据写入情况:
在这里插入图片描述
我们看到本地文件中的内容已经实现了数据的顺序写入。
完成后我们再用“ 读 ”模式打开该文件,并在判断非空后使用 fgetc 函数来顺序读取该文件中的内容:

int main()
{
	FILE* p = fopen("test.txt", "r");
	//文件打开模式为“读”
	if (p == NULL)
	{
		perror("FILE_OPEN");
		return 1;
	}
	int ch = 0;
	while ((ch = fgetc(p)) != EOF)
	{
		printf("%c ", ch);
		//顺序读取文件指针pp指向文件内的信息并打印
	}
	fclose(p);
	p = NULL;
	return 0;
}

将程序编译运行起来查看我们 fgetc 函数的读取结果:
在这里插入图片描述
并且我们也可以使用 fputs 函数(区别于 fputc 函数)来实现字符串的顺序写入:

int main()
{
	FILE* p = fopen("test.txt", "w");
	//文件打开模式为“写”
	if (p == NULL)
	{
		perror("FILE_OPEN");
		return 1;
	}
	fputs("The test TXT\n", p);
	//fputc 为写入字符,fouts 为写入字符串
	//只写入字符串内容,不会自动换行,想要换行需手动添加换行转义字符\n
	//并且在写入时,会覆盖原本的内容数据
	fputs("The test TXT", p);
	fclose(p);
	p = NULL;
	return 0;
}

或使用 fgets 函数(区别于 fgetc 函数)来实现字符串的顺序读取:

int main()
{
	FILE* p = fopen("test.txt", "r");
	//文件打开模式为“读”
	if (p == NULL)
	{
		perror("FILE_OPEN");
		return 1;
	}
	char arr[256] = { 0 };
	//定义字符数组用于存放读取到的字符串
	fgets(arr, 256, p);
	//从文件指针p指向文件处,读取最多256个字符,并将数据读取至字符数组arr中
	//该函数为按行读取,读取至换行转义符\n处主动停止并换行
	printf("%s", arr);
	//想要读取两行就需要使用两次fgets函数
	fgets(arr, 256, p);
	printf("%s", arr);
	fclose(p);
	p = NULL;
	return 0;
}

最终目的,就是要结合文件操作将数据保存至本地硬盘中,从而实现优化,于是我们可以使用 fprintf 函数实现将结构体变量的内容保存至本地硬盘之中:

typedef struct Contact
{
	char name[20];
	char sex[5];
	int age;
	char tele[11];
}con;
int main()
{
	FILE* p = fopen("test.txt", "w");
	//文件打开模式为“写”
	if (p == NULL)
	{
		perror("FILE_OPEN");
		return 1;
	}
	con c1 = { "Sherry","女",18,"3478290" };
	fprintf(p, "%s %s %d %s\n", c1.name, c1.sex, c1.age, c1.tele);
    //按照"%s %s %d %s\n"的格式将数据c1.name, c1.sex, c1.age, c1.tele写入至p所指向的文件内
	fclose(p);
	p = NULL;
	return 0;
}

程序编译运行结束后关闭,这时我们再去本地文件中查看会发现,数据已经成功的保存至本地硬盘中了:
在这里插入图片描述

并且我们也可以通过 fscanf 函数从本地硬盘文件中读取数据:

typedef struct Contact
{
	char name[20];
	char sex[5];
	int age;
	char tele[11];
}con;
int main()
{
	FILE* p = fopen("test.txt", "r");
	//文件打开模式为“读”
	if (p == NULL)
	{
		perror("FILE_OPEN");
		return 1;
	}
	con c1 = { 0 };
	fscanf(p, "%s %s %d %s", c1.name, c1.sex, &(c1.age), c1.tele);
	//按照"%s %s %d %s"的格式,从p所指向的文件中将数据读取至c1.name, c1.sex, &(c1.age), c1.tele中
	printf("%s %s %d %s\n", c1.name, c1.sex, c1.age, c1.tele);
	fclose(p);
	p = NULL;
	return 0;
}

在这里插入图片描述

3. 文件随机读写:

我们很多时候并不是要进行顺序读写,而是进行随机读写(伪随机,指不按照顺序依次进行读写)。为了实现这样的操作,我们就需要使用 fseekftellrewind 三个函数来帮助我们对这样的操作进行实现。

3.1 fseek 函数:

fseek 函数的作用为,根据文件指针的位置和偏移量来定位文件指针。

int fseek(FILE* strname, long int offset, int origin);

1.“ offset”为相对于指针位置的指针偏移量
2.“ origin ”为指针位置,其参数有三种:“ SEEK_CUR ”表示文件指针当前位置;“ SEEK_END ”表示文件末尾的位置;“ SEEK_SET ”表示文件开始位置。

int main()
{
	FILE* p = fopen("test.txt", "r+");
	//文件打开模式为“读写”
	if (p == NULL)
	{
		perror("FILE_OPEN");
		return 1;
	}
	char ch = 'a';
	for (ch = 'a'; ch <= 'z'; ch++)
	{
		fputc(ch, p);
		//使用 fputc 函数顺序写入小写字符a~z
	}
	fseek(p, 10, SEEK_SET);
	//使用fseek函数将文件指针从文件开始处(参数SEEK_SET表示文件起始位置)指向偏移量为10处
	//偏移量为正表示向后偏移,为负表示向前偏移
	char output;
	output = fgetc(p);
	//接下来进行读取时,继续向后读取一个字符,即字符k
	printf("%c\n", output);
	fclose(p);
	p = NULL;
	return 0;
}

在这里插入图片描述

3.2 ftell 函数:

 long int ftell(FILE* strname);

ftell 函数的作用为,返回文件指针相对于文件起始位置的偏移量。

int main()
{
	FILE* p = fopen("test.txt", "r+");
	//文件打开模式为“读写”
	if (p == NULL)
	{
		perror("FILE_OPEN");
		return 1;
	}
	char ch = 'a';
	for (ch = 'a'; ch <= 'z'; ch++)
	{
		fputc(ch, p);
		//使用 fputc 函数顺序写入小写字符a~z
	}
	fseek(p, -5, SEEK_END);
	//使用fseek函数将文件指针从文件结尾处(参数SEEK_SET表示文件起始位置)指向偏移量为-5处
	//偏移量为正表示向后偏移,为负表示向前偏移
	long back = ftell(p);
	//定义整型变量用于接受并记录指针相对于起始位置的偏移量
	printf("指针相对于起始位置的偏移量为:%ld\n", back);
	fclose(p);
	p = NULL;
	return 0;
}

在这里插入图片描述

3.3 rewind 函数:

void rewind(FILE* strname);

rewind 函数的作用为,使文件指针位置返回文件的起始位置

int main()
{
	FILE* p = fopen("test.txt", "r+");
	//文件打开模式为“读写”
	if (p == NULL)
	{
		perror("FILE_OPEN");
		return 1;
	}
	char ch = 'a';
	for (ch = 'a'; ch <= 'z'; ch++)
	{
		fputc(ch, p);
		//使用 fputc 函数顺序写入小写字符a~z
	}
	fseek(p, -5, SEEK_END);
	rewind(p);
	//使文件指针回归文件起始位置
	printf("%c\n", fgetc(p));
	//打印验证指针当前位置
	fclose(p);
	p = NULL;
	return 0;
}

在这里插入图片描述

4. 文本文件与二进制文件:

根据数据的组织形式,我们将数据文件称为文本文件二进制文件
二进制文件:在我们的计算机内存中,各种数据都是以二进制码的形式进行存储的,以 二进制码形式进行存储的文件
文本文件:以 ASCII 字符形式进行存储的文件
如果我们想要在外存上以 ASCII 码的形式存储数据,就需要在存储前将数据进行转换
数据在内存中数据到底是如何让进行存储的呢?
实际上,字符在内存中的存储一律是以 ASCII 码的形式进行存储的,而数值型数据既可以用ASCII 码存储,也可以用二进制形式进行存储。

例如十进制数字 10000 在进行存储时,就可以有两种存储形式:
1.二进制形式:
00000000 00000000 00100111 00010000
2.ASCII码形式:
00110001 00110000 00110000 00110000 000110000
1 0 0 0 0


int main()
{
	int a = 10000;
	FILE* p = fopen("test.txt", "wb");
	//“wb”表示以只写模式打开二进制文件
	if (p == NULL)
	{
		perror("FileOpen");
		return 0;
	}
	fwrite(&a, 4, 1, p);
	//将变量a中的数据,每四个字节存储一次,写入文件指针p所指向的文件
	fclose(p);
	p = NULL;
	return 0;
}

在上面这段代码运行成功后,我们已经成功的将变量 a 中的数据写入到了本地磁盘对应的 txt 文件中了,可是我们发现,当我们尝试打开本地文件查看存储的数据时,里面看起来并不是我们想要的结果:
在这里插入图片描述
是我们的程序哪里出错了吗?其实并不是,而是因为我们使用了" wb "方式,即以二进制形式进行了写入,所以我们在尝试直接查看时显示的是二进制符号。
所以我们就需要换一种方式才能对我们的文件内容进行查看。首先选中我们的“ 源文件 ”栏,右击选择“ 添加 ” -> “ 添加现有项 ”,将写入时创建的 txt 文件添加进来
在这里插入图片描述
然后选中 txt 文件,右击选择“ 打开方式 ”选项
在这里插入图片描述

接着在选项框中下拉选择“ 二进制编辑器 ”
在这里插入图片描述
这时我们就看到了文件内的实际存储情况了:

在这里插入图片描述

它显示我们的文件中的实际存储数据为 10 27 00 00,这又是怎么来的呢?这是因为,我们在存储时根据语句:

fwrite(&a, 4, 1, p);

根据这条语句,我们在进行数据写入时,是四个字节一组进行写入的,于是根据其二进制码可以得到它的存储为:

每四个字节进行划分:
        0000 0000 0000 0000 0010 0111 0001 0000
于是得到:
        00 00 27 10

又因为在之前我们就验证过我的计算机采用的是小端存储模式,于是在进行压栈时会将数据进行倒置存储,于是就有:

10 27 00 00

5. 文件读取结束的判定:

5.1 错误使用 feof 函数:

  1. 在文件的读取过程中,不能通过 feof 函数的返回值来判定文件是否读取结束。
  2. 该函数的作用为,在已经确定文件读取结束的情况下,用于判定文件读取结束的原因

5.2 判断文件读取结束:

如何正确判断文件是否读取结束?

文本文件判断文件读取结束方法:
①. 使用 fgetc 函数判断是否为 EOF
②. 使用 fgets 函数判断返回值是否为 NULL

#include<stdio.h>
#include<stdlib.h>
int main()
{
    int c; 
    //注意:int,非char,要求处理EOF
    FILE* fp = fopen("test.txt", "r");
    if (!fp)
    {
        perror("File opening failed");
        return 1;
    }
    // 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);
    fp = NULL;
	return 0;
}

二进制文件判断文件读取结束方法:
使用 fread 函数判断返回值是否小于实际要读取的数据个数。

#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);
    fp = NULL;
    return 0;
}

在这里插入图片描述

6. 文件缓冲区:

文件缓冲区是用以暂时存放读写期间的文件数据而在内存区预留的一定空间。通过磁盘缓存来实现,磁盘缓存不是一种实际存在的存储介质,它依托于固定磁盘,提供对主存储器存储空间的扩充,即利用主存中的存储空间, 来暂存从磁盘中读出 (或写入)的信息。
例如在国际 ANSI C 标准中,就是采用“ 缓冲文件系统 ”来对数据文件进行处理的。缓冲文件系统会自动地在我们的内存空间中为程序中的每个正在使用的文件开辟一块“ 文件缓冲区 ”。

计算机内存中向本地磁盘中输出数据:
将会先送至缓冲区->将缓冲区全部装满后->一并送达磁盘。
从磁盘向计算机读入数据:
从磁盘文件中读取数据->并将其输入至缓冲区->并在充满缓冲区后再逐个地将数据送达程序数据区

而至于缓冲区的大小,则是由 C 编译系统决定的
验证缓冲区:

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

因为缓冲区的存在,数据只有在填满缓冲区后才会进行真正的写入或读取,所以在 C 语言程序代码的编写过程中,在对文件进行操作时,需要刷新缓冲区并在文件操作结束时关闭文件,否则就可能导致文件的读写操作出现问题

7.总结:

今天我们了解了文件操作与管理的相关知识,学习了文件的顺序读写、随机读写、文件读取结束的判定以及文件缓冲区的相关介绍,并且对文本文件和二进制文件有了一定的了解和区分,通过文件操作,可以实现对本地文件的修改与维护,希望我的文章和讲解能对大家的学习提供一些帮助。

当然,本文仍有许多不足之处,欢迎各位小伙伴们随时私信交流、批评指正!我们下期见~

在这里插入图片描述

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

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

相关文章

优思学院:《改变世界的机器・精益生产之道》是什么著作?

《改变世界的机器》&#xff08;The Machine That Changed the World&#xff09;是一本经典的商业管理书籍&#xff0c;由詹姆斯P温斯顿&#xff08;James P. Womack&#xff09;、丹尼尔T琼斯&#xff08;Daniel T. Jones&#xff09;和丹尼尔罗斯&#xff08;Daniel Roos&am…

带组态物联网平台源码 代码开源可二次开发 web MQTT Modbus

物联网IOT平台开发辅助文档 技术栈&#xff1a;JAVA [ springmvc / spring / mybatis ] 、Mysql 、Html 、 Jquery 、css 使用协议和优势&#xff1a; TCP/IP、HTTP、MQTT 通讯协议 1.1系统简介 IOT通用物联网系统平台带组态&#xff0c;是一套面向通用型业务数据处理的系统…

Spring MVC 源码- HandlerAdapter 组件(五)之 HttpMessageConverter

HandlerAdapter 组件HandlerAdapter 组件&#xff0c;处理器的适配器。因为处理器 handler 的类型是 Object 类型&#xff0c;需要有一个调用者来实现 handler 是怎么被执行。Spring 中的处理器的实现多变&#xff0c;比如用户的处理器可以实现 Controller 接口或者 HttpReques…

数据结构预算法之买卖股票的最好时机(三)动态规划

目录&#xff1a;一.题目知识点&#xff1a;动态规划二.动态规划数组思路确定1.dp数组以及下标的含义2.确定递推公式3.dp数组如何初始化4.确定遍历顺序5.举例推导dp数组一.题目知识点&#xff1a;动态规划动态规划算法的基本思想是&#xff1a;将待求解的问题分解成若干个相互联…

惠普m1136打印机驱动程序安装教程

惠普m113打印机是一款功能强大的多功能打印机&#xff0c;它能够打印、复印、扫描和传真等。如果你要使用这款打印机&#xff0c;你需要下载并安装驱动程序&#xff0c;以确保它能够在你的计算机上正常工作。在本文中&#xff0c;我们将介绍如何下载和安装惠普m1136打印机驱动程…

Python实现贝叶斯优化器(Bayes_opt)优化支持向量机回归模型(SVR算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。1.项目背景贝叶斯优化器 (BayesianOptimization) 是一种黑盒子优化器&#xff0c;用来寻找最优参数。贝叶斯优化器是…

【华为OD机试模拟题】用 C++ 实现 - 跳格子(2023.Q1)

最近更新的博客 华为OD机试 - 入栈出栈(C++) | 附带编码思路 【2023】 华为OD机试 - 箱子之形摆放(C++) | 附带编码思路 【2023】 华为OD机试 - 简易内存池 2(C++) | 附带编码思路 【2023】 华为OD机试 - 第 N 个排列(C++) | 附带编码思路 【2023】 华为OD机试 - 考古…

sklearn学习-朴素贝叶斯(二)

文章目录一、概率类模型的评估指标1、布里尔分数Brier Score对数似然函数Log Loss二、calibration_curve&#xff1a;校准可靠性曲线三、多项式朴素贝叶斯以及其变化四、伯努利朴素贝叶斯五、改进多项式朴素贝叶斯&#xff1a;补集朴素贝叶斯ComplementNB六、文本分类案例TF-ID…

excel核对技巧:这么多数据对比的方法应该够用了

日常工作不时会需要对比数据&#xff0c;查找差异&#xff0c;查找重复值等。有的是对比同一工作表中的数据&#xff0c;有的是对比不同工作表之间的数据。希望接下来介绍的多种Excel数据对比方法&#xff0c;让大家能在不同情况下都能快速完成数据的对比。第一部分&#xff1a…

pytorch入门1--数据操作(张量)

一、张量的定义和变换 1.张量表示一个数值组成的数组&#xff0c;这个数组可能有多个维度。 说明&#xff0c;torch.arange(12)可以得到一个一维的&#xff08;有几层中括号就是几维数组&#xff0c;注意是层&#xff0c;不是个数&#xff09;&#xff0c;一个最内层的一个中括…

Qt图片定时滚动播放器

目录参考结构PicturePlay.promain.cpppictureplay.hpictureplay.cpppictureplay.ui效果参考 Qt图片浏览器 QT制作一个图片播放器 Qt中自适应的labelpixmap充满窗口后&#xff0c;无法缩小只能放大 可以显示jpg、jpeg、png、bmp。可以从电脑上拖动图到窗口并显示出来或者打开文件…

371. 两整数之和

题目&#xff1a; 给你两个整数 a 和 b &#xff0c;不使用 运算符 和 - &#xff0c;计算并返回两整数之和。 示例 1&#xff1a; 输入&#xff1a;a 1, b 2 输出&#xff1a;3 示例 2&#xff1a; 输入&#xff1a;a 2, b 3 输出&#xff1a;5 提示&#xff1a; -…

虚拟机VMware Workstation Pro环境搭建

VMware Workstation Pro是一款虚拟化工具&#xff0c;允许用户在Windows PC上运行多个操作系统。这个平台提供一个安全和独立的环境&#xff0c;让用户在使用前&#xff0c;可以建立和测试应用程序、检查修补程序&#xff0c;以及尝试不同的操作系统。它附有虚拟机库 它允许用户…

【大数据】大数据Hadoop生态圈

文章目录大数据Hadoop生态圈-组件介绍1、HDFS&#xff08;分布式文件系统&#xff09;2、MapReduce&#xff08;分布式计算框架&#xff09;3、Spark&#xff08;分布式计算框架&#xff09;4、Flink&#xff08;分布式计算框架&#xff09;5、Yarn/Mesos&#xff08;分布式资源…

LeetCode 热题 C++ 148. 排序链表 152. 乘积最大子数组 160. 相交链表

力扣148 给你链表的头结点 head &#xff0c;请将其按 升序 排列并返回 排序后的链表 。 示例 1&#xff1a; 输入&#xff1a;head [4,2,1,3] 输出&#xff1a;[1,2,3,4]示例 2&#xff1a; 输入&#xff1a;head [-1,5,3,4,0] 输出&#xff1a;[-1,0,3,4,5]示例 3&#x…

php mysql校园帮忙领取快递平台

1、后台管理员用户名hsg 密码hsg 2、开发语言&#xff1a;PHP&#xff0c;数据库为MySql 3、数据库连接字符串在conn.php中修改 4、运行环境wamp5.1.7或者appserv2.5.9 5.程序编码gbk.不支持php5.3以上版本 6.本人发布的程序一律享有免费运行一次…

西安银行就业总结

引 进银行性价比最高的时刻是本科&#xff0c;研究生的话可以去需要研究生较多的银行&#xff0c;比如邮储或者证券类的中信建投。中信建投很香&#xff0c;要求本硕西电。研究生学历的话&#xff0c;一般情况下银行不会卡本科&#xff0c;只看最高学历&#xff0c;部分银行需…

内核并发消杀器(KCSAN)技术分析

一、KCSAN介绍KCSAN(Kernel Concurrency Sanitizer)是一种动态竞态检测器&#xff0c;它依赖于编译时插装&#xff0c;并使用基于观察点的采样方法来检测竞态&#xff0c;其主要目的是检测数据竞争。KCSAN是一种检测LKMM(Linux内核内存一致性模型)定义的数据竞争(data race)的工…

网络应用之URL

URL学习目标能够知道URL的组成部分1. URL的概念URL的英文全拼是(Uniform Resoure Locator),表达的意思是统一资源定位符&#xff0c;通俗理解就是网络资源地址&#xff0c;也就是我们常说的网址。2. URL的组成URL的样子:https://news.163.com/18/1122/10/E178J2O4000189FH.html…

最好的个人品牌策略是什么样的

在这个自我营销的时代&#xff0c;个人品牌越来越受到人们的重视。您的个人品牌的成功与否取决于您在专业领域拥有的知识&#xff0c;以及拥有将这些知识传达给其他用户的能力。如果人们认为您没有能力并且无法有效地分享有用的知识&#xff0c;那么您就很难获得关注并实现长远…