C语言之文件操作(详解版)

不知不觉我们已经学到C语言的文件操作部分了,这部分内容其实很有意思,因为它可以直接把我们代码中的数据写入硬盘,而不是我们关掉这个程序,代码就没有了,让我们开始学习吧!


目录

1.为什么使用文件

2.什么是文件

2.1程序文件

2.2数据文件

2.3文件名

3.文件的打开和关闭

3.1文件指针

3.2文件的打开和关闭

3.2.1fopen:文件打开函数

3.2.2fclose:关闭文件函数

3.2.3代码示例

3.2.4文件打开(fopen)模式

4.文件读写顺序

4.1文件的顺序读写

4.1.1fputc函数

4.1.2fgetc函数

代码示例

4.1.3fputs函数

4.1.4fgets函数

代码示例

4.1.5fprintf函数

4.1.6fscanf函数

代码示例

4.1.7fwrite函数

4.1.8fread函数

代码示例

4.2文件的随机读写

4.2.1fseek函数

4.2.2ftell函数

4.2.3rewind函数

代码示例

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


1.为什么使用文件

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

数据存放在内存中:

前面实现的通讯录,当程序运行起来的时候,可以给通讯录增加,删除数据,但是当程序退出的时候,通讯录中的数据自然就不存在了,当下次运行程序的时候,数据又得重新录入,这样的通讯录就很局限

数据存放在硬盘中:

可以把数据记录下来,只有我们自己选择删除数据的时候,数据才会被销毁,否则,我们下次打开这个程序的时候,上一次存入的数据都存在,不会消失。(下篇博客为大家实现)

保持存入通讯录的数据一直存在,这就涉及到我们数据持久化问题

2.我们一般把数据持久化的方法有:

把数据存放在磁盘文件

把数据存放到数据库等方式

3.我们要学的是把数据放到磁盘文件中

2.什么是文件

简单来说,磁盘上的文件就是文件,就比如我们计算机上C盘中的文件夹下的文件

以上都是存放在硬盘中的文件

在程序设计中,我们一般把文件分为两类(从文件功能的角度分):

程序文件

数据文件

我们主要学习数据文件

2.1程序文件

源程序文件(后缀为.c)

目标文件(windows环境后缀为.obj)

可执行程序(Windows环境下后缀为.exe)

2.2数据文件

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

数据在显示器上:

处理数据的输入输出都是以终端为对象的,就是从终端的键盘上输入数据,运行结果显示到显示器上

数据在磁盘文件中:

我们可以把信息输出到磁盘上,当需要的时候再从磁盘上把数据读取到内存中使用

2.3文件名

我们都一个文件要有唯一的文件标识,以方便用户的识别和引用

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

为了方便起见,文件标识就被认为是文件名

3.文件的打开和关闭

3.1文件指针

1.什么是文件指针:

在缓冲文件系统中,关键的概念是“文件类型指针”,简称“文件指针”,每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(例如:文件名,文件状态,文件当前位置),这些信息是保存在一个结构体变量中的。该结构体类型是由系统声明的,取名FILE

2.每当我们打开一个文件的时候,系统会根据文件的情况自动创建一个FILE结构的变量,并填充其中的信息,使用者不必关心其中的细节,一般都是通过FILE指针来维护这个FILE结构的变量,这样使用起来更加方便

3.我们创建一个FTLE*的指针变量,例如FILE* pf,它就是一个文件指针变量

相信很多伙伴们又要问为什么要创建这个指针变量:

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

3.2文件的打开和关闭

我们都知道,文件在读写之前,应该先打开文件,在使用结束之后关闭文件

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

接下来让我们学习一下,文件的打开(fopen)和关闭(fclose)这两个函数

3.2.1fopen:文件打开函数

1.函数功能:打开一个文件

2.头文件:#include<stdio.h>

3.函数格式:FILE *fopen( const char *filename, const char *mode );

filename:文件名

mode:文件打开方式(下面会为大家总结一个表格)

4.函数返回值:

打开文件成功:返回一个指向打开文件的指针

打开文件失败:返回一个空指针

所以我们每次在打开文件的代码下,要加一段代码来检测文件是否打开成功

3.2.2fclose:关闭文件函数

1.函数功能:关闭一个文件

2.头文件:#include<stdio.h>

3.函数格式:int fclose( FILE *stream );

stream:流,就是文件流

这里要为大家拓展关于“流”的知识

在我们C程序运行的时候,默认打开三个流

stdin:标准输入流(就是我们在键盘上可以输入的数据)

stdout:标准输出流(我们在屏幕上可以看到的数据)

stderr:标准错误流(我们在屏幕上可以看到的数据)

它们的类型都是FILE*

所以我们在写C程序的时候才不需要在打开流,因为它是默认打开这三个流的

在进行文件操作的时候,我们是没有默认打开流的,这时需要我们手动给它添加一个流

然后进行读取写入等操作

我们这里的 FILE *stream 就是一个文件流

例如:FILE* pf=(“test.txt”,"w");这个语句里,pf这个文件指针就是一个文件流

那么我们为什么要有流呢?我们的数据是不能直接传输到输出设备上的,它是通过流进行传输的,目前我们知道这些,进行文件操作的时候就不会觉得难以理解了。

4.函数返回值:

文件关闭失败:函数返回值是0,同时需要我们把文件指针置为NULL

文件关闭失败:函数返回EOF来指示错误

3.2.3代码示例

现在介绍完fopen和fclose函数了,让我们看个代码来进一步理解这两个函数的使用

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>int main()
{//打开一个文件,以只读的模式打开FILE* pf = fopen("test.txt", "r");//这里的文件名,如果我们想要使用//已经存在,也就是创建好的文件,我们需要把文件路径给完整的加上//检测文件是否打开成功,成功则进入文件,失败返回空指针if (pf == NULL){perror("fopen");return 1;}//进入文件,进行读文件//...//关闭文件fclose(pf);pf = NULL;return 0;
}

我们运行代码,发现显示了错误信息

提醒我们没有这个文件,这就引出了我们下一个知识点,文件打开模式有哪些,以只读模式打开文件为什么会打开失败。

3.2.4文件打开(fopen)模式

这里给大家总结了一个表格,我们可以对照表格,选择我们需要的文件打开模式

这里我们要注意,以写的形式打开一个文件时,上次书写在文件中的数据将会被销毁,这次打开文件输入的内容将覆盖上一次的内容

4.文件读写顺序

文件读写分为顺序读写和随机读写两类

我们在学习这部分内容之前,还需要明确一个知识点

在我们平时写C语言时,是面向程序的:数据显示到屏幕上

今天学习的面向文件操作:数据显示到文件中

知道输入和输出的面向关系,我们才能更好的学习这部分知识

4.1文件的顺序读写

文件的顺序读写就是,按顺序读写,一个诶一个

这里我们学习几个函数,来帮助我们更好的认识文件顺序读写

字符输入输出函数:fgetc/fputc

文本行输入输出函数:fgets/fputs

格式化输入输出函数:fscanf/fprintf

二进制输入输出函数:fread/fwrite

前三对函数适用于所有流(既适用于标准输出流,也适用于文件流)

最后一对仅适用于文件流

我们一对一对来介绍

4.1.1fputc函数

1.函数功能:将字符写入文件流或者标准输出流

2.头文件:#include<stdio.h>

3.函数格式:int fputc( int c, FILE *stream );

这里的c:要输出(写入)的字符

代码示例我们与fgetc函数放在一起实现

4.1.2fgetc函数

1.函数功能:从文件流或者标准输入流中读取字符

2.头文件:#include<stdio.h>

3.函数格式:int fgetc( FILE *stream );

4.函数返回值:

读取成功:返回作为int读取的字符

读取失败:返回EOF以指示错误或文件结束

下面我们来看个代码,理解这两个函数

代码示例

int main()
{//打开一个文件FILE* pf = fopen("test1.txt", "w");//以写的形式打开//判断文件是否打开成功if (pf == NULL){perror("fopen");return 1;}//文件打开成功,进行写文件fputcchar ch = 0;for (ch = 'a'; ch <= 'z'; ch++){fputc(ch, pf);}//书写完毕,关闭文件fclose(pf);pf = NULL;//打开这个文件,我们进行读取操作FILE* ptf = fopen("test1.txt", "r");//以读的形式打开if (ptf == NULL){perror("fopen");return 1;}//开始读取,我们读取四次int tmp = fgetc(ptf);printf("%c\n", tmp);tmp = fgetc(ptf);printf("%c\n", tmp);tmp = fgetc(ptf);printf("%c\n", tmp);tmp = fgetc(ptf);printf("%c\n", tmp);//读取完毕,关闭文件fclose(ptf);ptf = NULL;return 0;
}

打开文件所在文件夹,我们可以看到文件中已经存入数据,这是fputc函数的功能,在文件中写入了数据

运行代码,我们可以看到屏幕上的结果,读取到了a b c d ,这是fgetc函数的功能

4.1.3fputs函数

1.函数功能:将字符串写入文件流或者标准输出流

2.头文件:#include<stdio.h>

3.函数格式:int fputs( const char *string, FILE *stream );

string:我们需要写入的字符串

4.函数一次性只能写入一条字符串

代码示例我们与fgets函数放在一起实现

4.1.4fgets函数

1.函数功能:从文件流或者标准输入流中读取字符串

2.头文件:#include<stdio.h>

3.函数格式:char *fgets( char *string, int n, FILE *stream );

string:数据存储的位置,通俗来说,就是从stream中要读的字符串放到string中

n:要读取的最大字符数

4.函数返回值:

读取成功:返回该条字符串

读取失败:返回一个空指针NULL

5.函数一次性只能读取一条字符串

我们来看段代码,加深理解

代码示例

int main()
{//打开一个文件FILE* pf = fopen("test1.txt", "w");//以写的形式打开//判断文件是否打开成功if (pf == NULL){perror("fopen");return 1;}//文件打开成功,进行写文件fputcfputs("hello world!\n", pf);fputs("亚里士多德!\n", pf);fputs("hehe!\n", pf);//书写完毕,关闭文件fclose(pf);pf = NULL;//打开这个文件,我们进行读取操作FILE* ptf = fopen("test1.txt", "r");//以读的形式打开if (ptf == NULL){perror("fopen");return 1;}//开始读取char buf[30] = { 0 };fgets(buf, 5, ptf);//读取完毕,关闭文件fclose(ptf);ptf = NULL;return 0;
}

我们打开文件可以看到,文件中已经写入(fputs)三行数据

我们运行代码读取(fgets)第一行的数据

我们预想中的hello并没有出现,而是hell,这是因为要留一个字符位置来存放‘\0’,如果想要打印hello,要让n=6

4.1.5fprintf函数

1.函数功能:格式化把数据写入文件流或者标准输出流

2.头文件:#include<stdio.h>

3.函数格式:int fprintf( FILE *stream, const char *format [, argument ]...);

char *format:格式化控制字符串,就是说它以什么形式输出,例如%d %s %f

[argument ]...:可选参数,就是对应形式的打印参数是什么

4.函数返回值:

写入成功:返回写入的字节数

写入失败:函数中的每一个都会返回一个负值

代码示例我们与fscanf函数放在一起实现

4.1.6fscanf函数

1.函数功能:从文件流或者标准输入流中读取格式化数据

2.头文件:#include<stdio.h>

3.函数格式:int fscanf( FILE *stream, const char *format [, argument ]... );

char *format: 格式化控制字符串,就是说它以什么形式输入,例如%d %s %f

[argument ]...:可选参数,就是对应形式的打印参数是什么

4.函数返回值:

读取成功:返回成功转换和分配的字段数

读取失败:发生错误,或者在第一次转换之前到达文件流的末尾的情况下,则返回值为fscanf的EOF

返回值0表示未分配任何字段

我们来看段代码,进一步了解

代码示例

struct S
{char name[12];int age;float score;
};
int main()
{//打开一个文件struct S s1 = { "张翰",34,94.3 };FILE* pf = fopen("test1.txt", "w");//以写的形式打开//判断文件是否打开成功if (pf == NULL){perror("fopen");return 1;}//文件打开成功,进行写文件fprintffprintf(pf, "%s %d %f", s1.name, s1.age, s1.score);//书写完毕,关闭文件fclose(pf);pf = NULL;//打开这个文件,我们进行读取操作FILE* ptf = fopen("test1.txt", "r");//以读的形式打开if (ptf == NULL){perror("fopen");return 1;}//开始读取struct S s2 = { 0 };fscanf(ptf, "%s %d %f", s2.name,& (s2.age), &(s2.score));printf("%s %d %f\n", s2.name, s2.age, s2.score);//读取完毕,关闭文件fclose(ptf);pf = NULL;return 0;
}

我们这里的结构体中存放的就是格式化的数据

打开文件,发现文件中已经写入(fprintf)数据

运行代码读取(fscanf),屏幕上显示文件中的数据

4.1.7fwrite函数

1.函数功能:以二进制输出数据,将数据写入文件流

2.头文件:#include<stdio.h>

3.函数格式:size_t fwrite( const void *buffer, size_t size, size_t count, FILE *stream );

void *buffer:指向要写入的数据的指针

size:要写的元素的大小,即每个元素所占字节的大小

count:最多写入几个元素

FILE *stream:文件流

4.函数返回值:

写入成功:写入的完整项目数,即count

写入失败:该数字可能小于count,此外,如果发生错误,则无法确定文件位置指示器

代码示例我们与fread函数放在一起实现

4.1.8fread函数

1.函数功能:以二进制输入数据,从文件中读取数据

2.头文件:#include<stdio.h>

3.函数格式:size_t fread( void *buffer, size_t size, size_t count, FILE *stream );

buffer:数据存储位置

size:要读的元素的大小,即每个元素所占字节的大小

count:最多读取几个元素

4.函数返回值:

读取成功:返回实际读取的完整项目数,即count,如果发生错误或在达到count之前遇到文件末尾,则该数字可能小于count

读取失败:使用feof或ferror函数来区分读取错误和文件结束条件。如果大小或计数为0,则fread返回0,并且缓冲区内容不变。

接下来我们看段代码来加深了解

代码示例

//fwrite  fread
struct S
{char name[12];int age;float score;
};
int main()
{//打开一个文件struct S s1 = { "张翰",34,94.3 };struct S s3 = { "黄晓明",55,88.9 };FILE* pf = fopen("test1.txt", "wb");//以二进制写的形式打开//判断文件是否打开成功if (pf == NULL){perror("fopen");return 1;}//文件打开成功,进行写文件fwrite(&s1, sizeof(s1), 1, pf);fwrite(&s3, sizeof(s3), 1, pf);//书写完毕,关闭文件fclose(pf);pf = NULL;//打开这个文件,我们进行读取操作FILE* ptf = fopen("test1.txt", "rb");//以二进制形式打开要读的文件if (ptf == NULL){perror("fopen");return 1;}//开始读取struct S s2 = { 0 };fread(&s2, sizeof(s2),1,ptf);printf("%s %d %f\n", s2.name, s2.age, s2.score);fread(&s2, sizeof(s2), 1, ptf);printf("%s %d %f\n", s2.name, s2.age, s2.score);//读取完毕,关闭文件fclose(ptf);pf = NULL;return 0;
}

打开文件,我们发现文件中已经被写入(fwrite)二进制数据,我们是看不懂的

我们发现只有汉字我们可以看懂,这是因为汉字的二进制形式与汉字本身形式相同

运行代码,我们读取(fread)数据到屏幕上,屏幕上显示数据,读取成功

4.2文件的随机读写

文件顺序读写有对应的函数,同样,文件的随机读写也有对应的函数,我们在这里介绍3个对应函数,fseek  ftell rewind

我们继续往下了解

4.2.1fseek函数

1.函数功能:将文件指针移动到指定位置

2.头文件:#include<stdio.h>

3.函数格式:int fseek( FILE *stream, long offset, int origin );

offect:偏移量,也就是当前指针位置到目标位置的字节数

指针从左—>右,偏移量为正数

指针从右—>左,偏移量为负数

origin:起始位置,它还被定义了三个量

SEEK_SET:文件其实位置

SEEK_CUR:文件当前指针位置

SEEK_END:文件末尾

4.函数返回值:

读取成功:fseek将返回0

读取失败:它将返回一个非零值,在无法查找的设备上,返回值未定义

我们将代码例子与ftell函数和rewind函数放在一起

4.2.2ftell函数

1.函数功能:获取文件指针的当前位置,通俗来说,这个函数就是让我们来求偏移量的,也就是文件指针相较于起始位置的偏移量

2.头文件:#include<stdio.h>

3.函数格式:long int ftell( FILE *stream );

4.函数返回值:

读取成功:返回文件指针相较于起始位置的偏移量

读取失败:ftell返回–1L(偏移量),errno设置为errno.H中定义的两个常量之一

我们和rewind函数一起来 看代码例子

4.2.3rewind函数

1.函数功能:将文件指针重新定位到文件起始位置

2.头文件:#include<stdio.h>

3.函数格式:void rewind( FILE *stream );

我们来看个代码进一步加深理解这两个函数

代码示例

int main()
{FILE* pf = fopen("test2.txt", "w");if (pf == NULL){perror("fopen");return 1;}//在文件中写入abcdefgchar ch = 0;for (ch = 'a'; ch <= 'z'; ch++){fputc(ch, pf);}//写入完成,关闭文件fclose(pf);pf = NULL;//再次打开文件,进行随机读取文件FILE* ptf = fopen("test2.txt", "r");if (ptf == NULL){perror("fopen");return 1;}//先按顺序往下读3个字符char tmp = fgetc(ptf);//aprintf("%c\n", tmp);tmp = fgetc(ptf);//bprintf("%c\n", tmp);tmp = fgetc(ptf);//cprintf("%c\n", tmp);//读取完三次后,我们想再次读取b,而不是按顺序读取到d,此时//我们需要使用fseek函数fseek(ptf, -2, SEEK_CUR);//改变指针位置tmp = fgetc(ptf);printf("%c\n", tmp);//此时读取到b//假设在此时,我们不知道文件指针的当前位置,这时,我们就需要用到// ftell函数来求一下当前文件指针的偏移量printf("文件指针相较于起始位置的偏移量是%d\n", ftell(ptf));//得到这个文件指针偏移量后,我们想把文件指针归到文件起始位置// 这时需要用到我们的rewind函数rewind(ptf);//我们打印一个字符验证一下,查看是否文件指针回到了文件起始位置,如果// 回到了,则打印出来的是a//进行读取字符tmp = fgetc(ptf);printf("是起始字符;>%c \n", tmp);//读取完毕,关闭文件fclose(ptf);ptf = NULL;return 0;
}int main()
{FILE* pf = fopen("test2.txt", "w");if (pf == NULL){perror("fopen");return 1;}//在文件中写入abcdefgchar ch = 0;for (ch = 'a'; ch <= 'z'; ch++){fputc(ch, pf);}//写入完成,关闭文件fclose(pf);pf = NULL;//再次打开文件,进行随机读取文件FILE* ptf = fopen("test2.txt", "r");if (ptf == NULL){perror("fopen");return 1;}//先按顺序往下读3个字符char tmp = fgetc(ptf);//aprintf("%c\n", tmp);tmp = fgetc(ptf);//bprintf("%c\n", tmp);tmp = fgetc(ptf);//cprintf("%c\n", tmp);//读取完三次后,我们想再次读取b,而不是按顺序读取到d,此时//我们需要使用fseek函数fseek(ptf, -2, SEEK_CUR);//改变指针位置tmp = fgetc(ptf);printf("%c\n", tmp);//此时读取到b//假设在此时,我们不知道文件指针的当前位置,这时,我们就需要用到// ftell函数来求一下当前文件指针的偏移量printf("文件指针相较于起始位置的偏移量是%d\n", ftell(ptf));//得到这个文件指针偏移量后,我们想把文件指针归到文件起始位置// 这时需要用到我们的rewind函数rewind(ptf);//我们打印一个字符验证一下,查看是否文件指针回到了文件起始位置,如果// 回到了,则打印出来的是a//进行读取字符tmp = fgetc(ptf);printf("是起始字符;>%c \n", tmp);//读取完毕,关闭文件fclose(ptf);ptf = NULL;return 0;
}

运行结果

在这里,我们要特别说明一下那个文件光标位置

打开我们写入的文件,我们发现光标在文件起始位置,这是因为文件指针默认指向第一个字符,当我们一次往后读取(fgetc)字符时,文件指针会自增1,会直接往下走,而不是一直打印那一个字符,这个不需要我们程序员来操作。

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

什么是文本文件,什么又是二进制文件?

1.根据数据的组织形式,数据文件被称为文本文件或者二进制文件

2.数据在内存中以二进制的形式存储,如果不加转换的输出到外存,就是二进制文件

(ps:这种二进制文件,我们一般是看不懂的,看不懂思密达!!!)

3.如果要求在外存上以ASCII码的形式存储,则需要在存储前转换,以ASCII码字符的形式存储的文件就是文本文件

(ps:看得懂思密达!!!)

我们举个简单的例子来看什么是二进制存储,什么是ASCII存储

例如我们要把整数10000存入内存中

它在内存中原来就是以二进制的补码形式存储的,也就是

00000000 00000000 00100111 00010000

(不清楚源码反码补码关系的伙伴可以去我这篇博客中了解源码反码补码的关系)

以文本文件(ASCII形式)存储:

这是整数10000,它的五个位数一次转换为ASCII对应值,也就是

以二进制的形式存储:

就是不加转换的二进制码:00000000 00000000 00100111 00010000

它在文件中显示出来的数据我们是看不懂的

可以举个代码例子

int main()
{//以二进制的形式进行写入FILE* pf = fopen("test3.txt", "wb");if (pf == NULL){perror("fopen");return 1;}int a = 10000;fwrite(&a, 4, 1, pf);fclose(pf);pf = NULL;//以二进制的形式进行读取FILE* ptf = fopen("test3.txt", "rb");if (ptf == NULL){perror("ptf::fopen");return 1;}int b = 0;fread(&b, 4, 1, ptf);printf("%d \n", b);fclose(ptf);ptf = NULL;return 0;
}

我们打开对应的文件,可以看到里面存储的数据


由于这篇博客字数已经到极限了,我们还剩下一点内容,文件读取结束的判定和文件缓冲区,我们放到下一篇博客,好了,大家下期再见!!!

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

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

相关文章

Adobe ME下载、Media Encoder下载

Media Encoder 2021 是一款可以帮助Adobepremiere pro和Adobe After Effects的用户使用集成视频编码器进行创作的视频和音频编码软件。Media Encoder 2021 mac新版本中针对上一个版本进行了多方面的改进与优化&#xff0c;提升了软件的性能与支持文件格式提升&#xff0c;有需要…

从零开始搭建React+TypeScript+webpack开发环境-基于lerna的webpack项目工程化改造

项目背景 在实际项目中&#xff0c;我们的前端项目往往是一个大型的Webpack项目&#xff0c;结构较为复杂。项目根目录下包含了各种配置文件、源代码、以及静态资源&#xff0c;整体布局相对扁平。Webpack的配置文件分散在不同的部分&#xff0c;包括入口文件、输出目录、加载…

文本生成高精准3D模型,北京智源AI研究院等出品—3D-GPT

北京智源AI研究院、牛津大学、澳大利亚国立大学联合发布了一项研究—3D-GPT&#xff0c;通过文本问答方式就能创建高精准3D模型。 据悉&#xff0c;3D-GPT使用了大语言模型的多任务推理能力,通过任务调度代理、概念化代理和建模代理三大模块&#xff0c;简化了3D建模的开发流程…

C++ | 继承和多态

目录 继承 继承的概念及用法 继承的作用域 向上转型和向下转型 继承过程中的默认生成函数 菱形继承及其解决方案 - 虚继承 虚继承的原理 - 虚基类表 继承和组合 多态 虚函数 多态的定义及使用 纯虚函数与抽象类 多态的原理 小点补充 虚表的位置 父类指针new一个…

django 批量 serializers listserializers

Django drf 序列化器 序列化器 扩展serializers的有用性是我们想要解决的问题。但是&#xff0c;这不是一个微不足道的问题&#xff0c;而是需要一些严肃的设计工作。— Russell Keith-Magee, Django用户组 序列化器允许把像查询集和模型实例这样的复杂数据转换为可以轻松渲染…

conda修改虚拟环境名称

conda 修改虚拟环境名称 conda 不能直接更改名称&#xff0c;但是可以通过克隆环境解决 新建环境&#xff08;克隆旧环境&#xff09; conda create --name 新环境名 --clone 旧环境名 删除原环境 conda remove --name 旧环境名 --all 查看现有环境 conda env list conda i…

Spring boot 整合grpc 运用

文章目录 GRPC基础概念&#xff1a;Protocol Buffers&#xff1a;proto 基础语法&#xff1a;调用类型&#xff1a; Spring boot 整合 grpc项目结构&#xff1a;整合代码&#xff1a;父 pomproto 模块服务端&#xff1a;客户端&#xff1a;实际调用&#xff1a; 原生集成 GRPC基…

SDN和NFV笔记

目录 SDN SDN的引入 SDN的概念 SDN网络部署的方式 SDN架构 OpenFlow SDN与传统网络的区别 SDN的应用 SDN的优点 NFV NFV的概念&#xff1a; NFV的架构&#xff1a; NFV相比于传统物理网元&#xff1a; NFV与SDN的关系 NFV与SDN的相似点 NFV与SDN的不同 SDN SD…

CVE-2023-25194 Kafka JNDI 注入分析

Apache Kafka Clients Jndi Injection 漏洞描述 Apache Kafka 是一个分布式数据流处理平台&#xff0c;可以实时发布、订阅、存储和处理数据流。Kafka Connect 是一种用于在 kafka 和其他系统之间可扩展、可靠的流式传输数据的工具。攻击者可以利用基于 SASL JAAS 配置和 SASL …

计算机毕业设计 基于Web的视频及游戏管理平台的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

OSG交互:选中场景模型并高亮显示

1、目的 可以在osg视图中选中指定模型实体,并高亮显示。共分为两种,一种鼠标点选,一种框选。 2、鼠标点选 2.1 功能说明 生成两组对象,一组cow对象可以被选中,另一组robot不能被选中;点击cow对象被选中高亮,点击robot被选中不高亮;点击空白处,弹出“select nothing!…

【Git】Git的GUI图形化工具ssh协议IDEA集成Git

一、GIT的GUI图形化工具 1、介绍 Git自带的GUI工具&#xff0c;主界面中各个按钮的意思基本与界面文字一致&#xff0c;与git的命令差别不大。在了解自己所做的操作情况下&#xff0c;各个功能点开看下就知道是怎么操作的。即使不了解&#xff0c;只要不做push操作&#xff0c;…

Java,多线程,线程的两种创建方式

首先是多线程的一些相关概念&#xff1a; 相关概念&#xff1a; 程序&#xff08;program&#xff09;&#xff1a;为完成特定任务&#xff0c;用某种语言编写的一组指令的集合。即指一段静态&#xff08;指不在执行中&#xff09;的代码。 进程&#xff08;process&#xf…

中国电信终端产业联盟5G Inside行业子联盟正式成立!宏电股份作为副理事单位受邀加入

11月9日&#xff0c;中国电信于广州召开“2023中国电信终端生态合作暨中国电信终端产业联盟&#xff08;以下简称CTTA&#xff09;第十四次会员大会”&#xff0c;联盟成员齐聚现场。作为CTTA大会的一个重要环节&#xff0c;中国电信终端产业联盟5G Inside行业子联盟正式成立&a…

[PyTorch][chapter 61][强化学习-免模型学习 off-policy]

前言&#xff1a; 蒙特卡罗的学习基本流程&#xff1a; Policy Evaluation : 生成动作-状态轨迹,完成价值函数的估计。 Policy Improvement: 通过价值函数估计来优化policy。 同策略&#xff08;one-policy&#xff09;&#xff1a;产生 采样轨迹的策略 和要改…

美国材料与试验协会ASTM发布新版玩具安全标准 ASTM F963-23

美国材料与试验协会ASTM发布新版玩具安全标准 ASTM F963-23 2023年10月13日&#xff0c;美国材料与试验协会&#xff08;ASTM&#xff09;发布了新版玩具安全标准ASTM F963-23 ​根据CPSIA的规定&#xff0c;当ASTM将ASTM F963的拟定修订意见通知CPSC时&#xff0c;若CPSC认为…

实战leetcode(二)

Practice makes perfect&#xff01; 实战一&#xff1a; 这里我们运用快慢指针的思想&#xff0c;我们的slow和fast都指向第一个节点&#xff0c;我们的快指针一次走两步&#xff0c;慢指针一次走一步&#xff0c;当我们的fast指针走到尾的时候&#xff0c;我们的慢指针正好…

使用Nginx和Spring Gateway为SkyWalking的增加登录认证功能

文章目录 1、使用Nginx增加认证。2、使用Spring Gateway增加认证 SkyWalking的可视化后台是没有用户认证功能的&#xff0c;默认下所有知道地址的用户都能访问&#xff0c;官网是建议通过网关增加认证。 本文介绍通过Nginx和Spring Gateway两种方式 1、使用Nginx增加认证。 生…

切换数据库的临时表空间为temp1 / 切换数据库的undo表空间为 undotbs01

目录 ​编辑 一、切换临时表空间 1、登录数据库 2、查询默认临时表空间 3、创建临时表空间temp1&#xff08;我们的目标表空间&#xff09; 4、修改默认temp表空间 5、查询用户默认临时表空间 6、命令总结&#xff1a; 二、切换数据库的undo表空间 1、查询默认undo表…

Wix使用velo添加Google ads tag并在form表单提交时向谷歌发送事件

往head里加代码时&#xff0c;不能看谷歌的代码&#xff0c;要看wix的代码&#xff0c;不然必定踩坑 https://support.wix.com/en/article/tracking-google-ads-conversions-using-wix-custom-code 这里的代码才对&#xff0c;因为wix搞了个velo&#xff0c;这个velo很傻x&am…