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; }
我们打开对应的文件,可以看到里面存储的数据
由于这篇博客字数已经到极限了,我们还剩下一点内容,文件读取结束的判定和文件缓冲区,我们放到下一篇博客,好了,大家下期再见!!!
相关文章:

C语言之文件操作(详解版)
不知不觉我们已经学到C语言的文件操作部分了,这部分内容其实很有意思,因为它可以直接把我们代码中的数据写入硬盘,而不是我们关掉这个程序,代码就没有了,让我们开始学习吧! 目录 1.为什么使用文件 2.什么…...
解决mac 下 docker-compose 不是命令
docker-compose docker: ‘compose’ is not a docker command #6569 解决方法: mkdir -p /usr/local/lib/docker ln -s /Applications/Docker.app/Contents/Resources/cli-plugins /usr/local/lib/docker/cli-plugins参考: https://github.com/docker/…...
test_sizeof
test_sizeof //结论: // sizeof(arrU8)得到的大小是u8类型数组的 **定义大小**,在 初始化的时候用 // strlen(arrU8)得到的大小是u8类型数组的 **实际大小**,在 复制的时候用 //sizeof((char*)arrU8),把一个u8 * 转成 char *&…...

100+ Windows运行命令大全,装B高手必备
操作电脑关闭、重启、注销、休眠的命令细则: 用法: shutdown [/i | /l | /s | /sg | /r | /g | /a | /p | /h | /e | /o] [/hybrid] [/soft] [/fw] [/f] [/m \\computer][/t xxx][/d [p|u:]xx:yy [/c "comment"]] 没有参数 显示帮助。这与键入 /? 是一样的。…...

iOS 设置图标和upload包时显示错误
右键-show in finder-AppIcon.appiconset-然后替换图片 然后遇到个问题 就是图片不能有alpha [Xcode]应用图标:ERROR ITMS-90717: “Invalid App Store Icon. The App Store Icon in the asset catalog in x… 具体操作:只需确保【AppIcon】图片集中不…...

软件工程的舞台上,《人月神话》的美学纷飞
前言: Hello大家好,我是Dream。 今天给大家分享一本书:《人月神话》——软件工程的经典之作。 《人月神话》是一本具有深远影响力的软件工程著作,无论是软件开发者、管理者还是学习软件工程的人士,都能从中获得宝贵的启…...
C现代方法(第19章)笔记——程序设计
文章目录 第19章 程序设计19.1 模块19.1.1 内聚性与耦合性19.1.2 模块的类型 19.2 信息隐藏19.2.1 栈模块 19.3 抽象数据类型19.3.1 封装19.3.2 不完整类型 19.4 栈抽象数据类型19.4.1 为栈抽象数据类型定义接口19.4.2 用定长数组实现栈抽象数据类型19.4.3 改变栈抽象数据类型中…...

Elasticsearch 作为 GenAI 缓存层
作者:JEFF VESTAL,BAHA AZARMI 探索如何将 Elasticsearch 集成为缓存层,通过降低 token 成本和响应时间来优化生成式 AI 性能,这已通过实际测试和实际实施进行了证明。 随着生成式人工智能 (GenAI) 不断革新从客户服务到数据分析…...

FPGA与STM32_FSMC总线通信实验
FPGA与STM32_FSMC总线通信实验 内部存储器IP核的参数设置创建IP核FPGA代码STM32标准库的程序 STM32F407 上自带 FSMC 控制器,通过 FSMC 总线的地址复用模式实现STM32 与 FPGA 之间的通信,FPGA 内部建立 RAM 块,FPGA 桥接 STM32 和 RAM 块&…...
maven配置自定义下载路径,以及阿里云下载镜像
1.配置文件 <?xml version"1.0" encoding"UTF-8"?> <settings xmlns"http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation"http://maven.apache.org…...
01.单一职责原则
单一职责原则 概述 简单来说就是一个类只描述一件事, 比如我们熟知的 userDao.java 只负责 用户域功能。如果userDao既操作user表又操作order表,这显然不合理。正确的做法是让orderDao.java去操作order表。 对类来说的,一个类应该只负责一项…...
RT-Thread上部署TinyMaix推理框架,使MCU赋予AI能力
概要 当谈到微控制器(MCU)和人工智能(AI)的结合,我们进入了一个激动人心的领域。传统上,AI应用程序需要大型计算机或云服务器的处理能力,但随着技术的发展,现在可以将AI嵌入到微控制器中。这为嵌入式系统、物联网设备、机器人和各种其他应用开启了新的可能性。 MCU A…...
设计模式 -- 策略模式(Strategy Pattern)
策略模式:一种行为型模式,这些设计模式特别关注对象之间的通信。在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法。 介绍 意图:定义一系列的算…...

Spring Boot 集成 ElasticSearch
1 加入依赖 首先创建一个项目,在项目中加入 ES 相关依赖,具体依赖如下所示: <dependency><groupId>org.elasticsearch</groupId><artifactId>elasticsearch</artifactId><version>7.1.0</version&g…...

百度智能云正式上线Python SDK版本并全面开源!
文章目录 1. SDK的优势2. 千帆SDK:快速落地LLM应用3. 如何快速上手千帆SDK3.1 SDK快速启动3.2 SDK进阶指引3.3 通过Langchain接入千帆SDK 4. 开源社区 百度智能云千帆大模型平台再次升级!在原有API基础上,百度智能云正式上线Python SDK&#…...

LeetCode(3)删除有序数组中的重复项【数组/字符串】【简单】
目录 1.题目2.答案3.提交结果截图 链接: 26. 删除有序数组中的重复项 1.题目 给你一个 非严格递增排列 的数组 nums ,请你** 原地** 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保…...

前端视角中的微信登录
目录 引入 流程介绍 具体实现 引入 本文主要讲解网站应用中微信登录的具体流程是怎么样的,以及作为前端开发人员在这整个流程中的主要任务是什么。 如果想要实现微信登录的功能,需要开发人员到微信开放平台注册相应的账号,进行注册应用&am…...
Python 中使用 Selenium 隐式等待
selenium 包用于使用 Python 脚本进行自动化和测试。 我们可以使用它来访问网页中的各个元素并使用它们。 该包中有许多方法可用于根据不同属性检索元素。 加载页面时,会动态检索一些元素。 与其他元素相比,这些元素的加载速度可能不同。 Python 中使用…...

GEE:基于 Landsat 计算的 kNDVI 应用 APP
作者:CSDN @ _养乐多_ 本文记录了在Google Earth Engine(GEE)平台中,使用 Landsat 遥感数据计算 kNDVI 的应用 APP 链接,并介绍该 APP 的使用方法和步骤。该APP可以为用户展示 NDVI 和 kNDVI 的遥感影像,进行对比分析。该 APP 在 Google Earth Engine(GEE)平台中实现。…...
Spring 缓存注解
Spring Cache 框架给我们提供了 Cacheable 注解用于缓存方法返回内容。但是 Cacheable 注解不能定义缓存有效期。这样的话在一些需要自定义缓存有效期的场景就不太实用。 按照 Spring Cache 框架给我们提供的 RedisCacheManager 实现,只能在全局设置缓存有效期。这…...

JavaSec-RCE
简介 RCE(Remote Code Execution),可以分为:命令注入(Command Injection)、代码注入(Code Injection) 代码注入 1.漏洞场景:Groovy代码注入 Groovy是一种基于JVM的动态语言,语法简洁,支持闭包、动态类型和Java互操作性,…...

C++实现分布式网络通信框架RPC(3)--rpc调用端
目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中,我们已经大致实现了rpc服务端的各项功能代…...

深入剖析AI大模型:大模型时代的 Prompt 工程全解析
今天聊的内容,我认为是AI开发里面非常重要的内容。它在AI开发里无处不在,当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗",或者让翻译模型 "将这段合同翻译成商务日语" 时,输入的这句话就是 Prompt。…...

全球首个30米分辨率湿地数据集(2000—2022)
数据简介 今天我们分享的数据是全球30米分辨率湿地数据集,包含8种湿地亚类,该数据以0.5X0.5的瓦片存储,我们整理了所有属于中国的瓦片名称与其对应省份,方便大家研究使用。 该数据集作为全球首个30米分辨率、覆盖2000–2022年时间…...
oracle与MySQL数据库之间数据同步的技术要点
Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异,它们的数据同步要求既要保持数据的准确性和一致性,又要处理好性能问题。以下是一些主要的技术要点: 数据结构差异 数据类型差异ÿ…...
数据链路层的主要功能是什么
数据链路层(OSI模型第2层)的核心功能是在相邻网络节点(如交换机、主机)间提供可靠的数据帧传输服务,主要职责包括: 🔑 核心功能详解: 帧封装与解封装 封装: 将网络层下发…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)
宇树机器人多姿态起立控制强化学习框架论文解析 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一) 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...

SpringTask-03.入门案例
一.入门案例 启动类: package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...

【笔记】WSL 中 Rust 安装与测试完整记录
#工作记录 WSL 中 Rust 安装与测试完整记录 1. 运行环境 系统:Ubuntu 24.04 LTS (WSL2)架构:x86_64 (GNU/Linux)Rust 版本:rustc 1.87.0 (2025-05-09)Cargo 版本:cargo 1.87.0 (2025-05-06) 2. 安装 Rust 2.1 使用 Rust 官方安…...

【MATLAB代码】基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),附源代码|订阅专栏后可直接查看
文章所述的代码实现了基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),针对传感器观测数据中存在的脉冲型异常噪声问题,通过非线性加权机制提升滤波器的抗干扰能力。代码通过对比传统KF与MCC-KF在含异常值场景下的表现,验证了后者在状态估计鲁棒性方面的显著优…...