当前位置: 首页 > news >正文

学习系统编程No.10【文件描述符】

引言:

北京时间:2023/3/25,昨天摆烂一天,今天再次坐牢7小时,难受尽在不言中,并且对于笔试题,还是非常的困难,可能是我做题不够多,也可能是没有好好的总结之前做过的一些题目,反正就是摆烂,而且刚刚看了一下蓝桥杯的题目,头大,虽然我5个月前就意识到了,并且5个月前相信我自己也许现在看到这种题目的时候,不会头大,没想到啊,往日依旧啊,一点进步没有,哈哈哈!所以从明天开始,我们开始整理做过的一些题目,争取掌握一些的做题技巧,所以今天我们就开始学学什么是基础IO和文件描述符,并且承接上篇博客的有关文件操作的知识

在这里插入图片描述

复习文件操作

从语言层面看文件操作:

具体请看该链接博客,该博客是我之前学习C语言时,总结的有关C语言文件操作,C语言文件操作详解,想要了解C语言(也就是语言层面)的文件操作,就看上述链接就行,我们把重点放在我们的系统层面文件操作,Linux操作系统


从系统层面看文件操作:

首先第一个接口肯定是如何打开文件的接口,就让我们一起看看Linux系统中的打开文件接口 open 吧!头文件: #include <sys/types.h> 、 #include <sys/stat.h> 和 #include <fcntl.h>
具体使用方式: int open(const char *pathname, int flags); 并且此时发现,该打开文件接口的返回值是一个int类型,并且此时open接口的第二个函数是一个int flags;的参数,第一个参数我们很好理解,代表的就是我们要打开的文件名,那这第二个参数代表的是什么意思呢?

想要知道第二个参数flags代表的是什么意思,此时我们就可以通过语言层面来推测,如我们知道,在C语言中,打开文件的使用方式是使用文件名和该文件的打开方式(w、r)来实现的,如下,FILE* fopen(const char* filename,const char* mode),并且发现,返回值是一个FILE*, fopen返回值类型的文件指针;所以我们可以间接的理解,系统接口open的第二个参数代表也是文件的打开方式,那么此时我们就会好奇,为什么可以使用一个整形来表示文件的打开方式呢?

所以此时为了搞定这个问题,我们就可以引出一个新的问题,搞懂这个问题,我们就搞懂了上述的问题:就是操作系统(OS)一般是如何让用户给自己传递标志位?


标志位相关知识理解

例如:我们想要给一个函数传递好几个标志位参数,int function(int flag1,int flag2,int flag3,……);我们一般使用的肯定是如上的方法,定义非常多个变量来进行多个标志位的传递,但是如果标志位有非常多呢?所以此时操作系统就做了一个处理,使用定义宏的方式,使用位图结构来解决传递多个标志位的问题,并且位图就是使用一个比特位来表示一个标志位,一个int就可以同时至少传递32个标志位,所以本质就是,位图的0/1结构可以代表非常多不同的值,从而通过这些不同的值,操作系统就可以识别出到底传了多少个标志位和这些标志位分别是什么,如下图所示:
在这里插入图片描述
所以此时我们就可以通过二进制标志位的方式来进行参数的传递,本质就是通过定义各种宏,代表相应的二进制标志位的值,然后通过按位与(&)的方式来限制这些宏执行的条件,并且通过按位或(|)的方式来表示同时可以执行的行为,所以此时我们就可以通过传递宏的方式来获取我们想要让代码执行的行为
如下图:

所以明白了上述的有关标志位的知识,此时我们就可以很好的理解,为什么系统调用接口open的第二个参数是一个整形参数,并且返回值也是一个整形了,就是因为操作系统在设计接口的时候,是通过标志位的形式来封装各种的有关文件读写权限,例如上述的1可以表示是读权限等!只有我们传递给操作系统接口的值为1或者为定义1的这个宏,此时我们才可以访问到系统调用中的文件打开的读权限(上述的 if 语句判断和按位与就行前提),所以如下图,就是操作系统中有关文件打开权限的宏定义,我们想要通过某种权限打开文件,此时就需要通过这些宏进行传参(本质就是标志位的传参)如图:就是系统中文件打开权限表示,宏定义

总结:未来我们封装一个函数,就可以给这个函数设置不同的标志位,并且将每一个标志位定义一个宏,最后在函数内部对宏值做判断,函数外部就可以通过宏的传递,进行相应标志位代表的行为的调用,这个也就是操作系统实现系统调用的一个常规设计思路


搞定了上述知识,此时我们就可以正式的来看一看什么是系统层面的文件操作了,但这边浅浅的再谈一句,就是例如C语言中的‘w’‘r’‘a’权限,本质都是通过对我们上述所说的对系统宏定义的标志位进行的再一次用户级封装而已;所以我们此时就可以理解, int open(const char *pathname, int flags);打开文件接口中的第二个参数int flags表示的意思和用法了 ,并且明白只要打开文件就一定要关系文件,所以在系统中关闭文件的接口close,头文件#include <unistd.h>,使用方法: int close(int fd); fd表示的意思就是打开文件后的那个返回值,同理C语言中,打开文件后的那个指向文件的指针,如下代码就是一个文件创建并打开,int fd = open(LOG, O_WRONLY | O_CREAT);使用两个宏定义的方式来表示读取文件和创建文件,但是如果此时按照上述写,我们可以发现,我们的LOG代表的文件的权限是乱码,所以此时就涉及到了创建文件是需要权限的问题,表示的意思就是,我们创建一个文件,一定需要给与这个文件相应的权限才可以,如果没有给,系统默认就是乱码,此时就引出有关文件打开的另一个参数模板, int open(const char *pathname, int flags, mode_t mode);这个模板就可以很好的解决上述的问题,可以让我们打开文件,创建文件的同时,赋予这个文件一定的权限,具体使用如下:int fd = open(LOG, O_WRONLY | O_CREAT, 0666); 这里的0666表示的就是赋予这个文件读写执行的所有权限,具体可以参照Linux权限那一节的相关知识(可以直接使用二进制来修改权限),Linux系统的权限问题,本质就是因为:100,010,001分别代表的是一个文件的读写执行权限,所以默认一个文件的创建就是拥有读写权限,所以我们添加的权限就是666权限(一个6表示读写权限,但是因为文件分为拥有者、所属组、other)所以是666权限,但是前提是不受umask影响,所以需要把umask设置为0,具体代码如下图:

搞定了打开和关闭文件,此时我们就来看一看如何写入、追加和读取文件中的数据,写入数据,头文件:#include <unistd.h>,使用方式: ssize_t write(int fd, const void *buf, size_t count);表示的意思:将buf数组中的大小为count的数据写入到fd被打开文件中,但是要注意,如果只使用原来的文件打开方式,在我们往文件中写入数据的时候,此时就不可以像C语言文件操作一样,文件内部会自己清空文件中的数据,所以在我们如果想要让文件打开时自动将文件中的内容清空,那么就需要在打开文件的时候多加一个宏定义的标志位,如该代码:int fd = open(LOG,O_WRONLY | O_CREAT | O_TRUNC,0666);多加了一个标志位,才可以让系统实现清理被打开文件的效果;搞定了写入,此时我们就来看看追加,本质追加就是一种写入,所以可以和上述的原理一样,我们只要把文件的打开方式改动一下,就可以了,如该代码: int fd = open(LOG, O_WRONLY | O_APPEND | O_CREAT,0666); ,所以只需要在打开文件的时候,加一个 O_APPEND 的宏定义标志位就行啦!并且将自动清理标志位去掉,因为自动清理标志位和追加标志位是矛盾的;搞定了追加,我们就再来看看什么是读取文件,同理:头文件 #include <unistd.h>,基本使用方式:ssize_t read(int fd, void *buf, size_t count);表示可以将一个fd被打开文件中的数据按照count大小读取到buffer数组中,具体使用如该代码ssize_t n = read(fd,buffer,sizeof(buffer)-1);,减一的原因在于,C语言文件操作和系统文件操作是不同的,C语言文件操作需要以\0结尾,但系统文件操作没有这个规定,并且还要注意的是,文件的打开方式需要发生改变, int fd = open(LOG,O_RDONLY)需要以读的方式来打开,并且因为读取文件已经存在,所以不需要给给权限,使用普通的系统文件打开接口就行

所以部分的文件打开方式如下:
在这里插入图片描述
本质就是可以通过宏定义的标志位来实现不同的行为,并且要注意文件打开方式不同,相应的读取、写入、追加效果都是不同的,所以注意要匹配使用!

总:还是那句话,任何语言中的文件操作,无论是读写还是追加等,都是像上述一样通过封装各种的宏定义标志位实现,也就是通过封装各种的系统调用接口实现而已

所以文件操作的本质都是被打开文件和进程之间的关系,我们学习的目标也就是进程和被打开文件之间的关系,所以按照内存来看,就是struct task_struct;和struct file;之间的关系,也就是进程控制块和文件对象之间的关系,所以无论是什么语言,都不可能直接跳过操作系统,直接去访问硬件,而是必须通过操作系统,进而贯穿体系结构,然后再间接访问到硬件,所以总的来说一句话,各种语言的本质都是对操作系统的系统调用接口进行的封装

体系结构图如下:
在这里插入图片描述


文件描述符

谈谈什么是文件描述符:
承接上述,我们把系统层面的文件操作给搞明白了,但是只是明白了像标志位传参这种比较表面的知识,所以接下来我们就谈谈像文件描述符这种比较内部的知识,所以什么是文件描述符呢?文件描述符就是,当我们打开一个文件之后,这个文件会有一个返回值int,我们一般使用 fd 来表示,所以此时这个被打开文件的fd返回值,就是我们要学习的文件描述符,所以这个返回值具体是用来干什么的呢?

想要明白这个问题,此时就要从别的知识点或者别的概念迁移,例,任何一个进程在启动的时候,默认会打开当前进程的三个文件:标准输入、标准输出和标准错误,如下表:

语言标准输入标准输出标准错误
C语言stdinstdoutstderr
C++cincoutcerr

所以无论是标准输入、标准输出还是标准错误,本质上这些东西都是文件而已,如下图:

在这里插入图片描述

因为Linux系统下一切皆是文件,所以,向显示器打印,本质就是向文件中写入,如何理解?

所以抽象成:
标准输入–设备文件–键盘文件
标准输出–设备文件–显示器文件
标准错误–设备文件–显示器文件

所以得出结论,任何一个进程启动,默认就是会直接打开三个文件,标准输入、标准输出和标准错误,这三个文件是不需要我们使用系统接口open来打开的,系统默认就是打开,所以此时我们明白,在我们自己使用open接口打开文件之前,系统就已经默认打开了三个文件(标准输入、标准输出和标准错误),所以明白了这点,我们就应该还可以明白,我们自己使用open打开的文件是存在返回值的,那么这三个文件肯定也是存在返回值的呀,所以,此时操作系统就规定,在文件描述符中,0表示标准输入,1表示标准输出,2表示标准错误,也就是表示,这三个默认打开的文件,它们默认的返回值就是0 1 2 ,也就意味着如果此时去打开一个新的文件,它的文件描述符只能从3开始,再打开一个文件文件描述符只能是4…所以文件描述符不仅代表的是文件打开后的返回值,本质上就是文件的编号,也就是文件的一个别名,以后操作系统就可以利用这些文件描述符,0 1 2 3 4,更加快速的找到对应的文件,所以这就是文件描述符的好处

并且从另一个方面来看问题,也就是操作系统可以利用这些文件描述符来管理文件,那么这些文件描述符的在操作系统内部本质上是什么呢?不难理解,从0 1 2 3……开始,这不就是一个数组吗?这不就是数组下标吗?所以本质上操作系统通过文件描述符对文件进行管理,本质就是通过数组(线性表)的方式对文件进行管理(增删查改)

被打开文件和进程之间的联系

所以当用户想要访问一个文件,操作系统一定要先管理好文件对象,问题,对应的打开文件的并不是文件自己,而是用户通过进程的方式通过操作系统去打开一个文件 ,所以还是要以进程的形式去访问文件,所以本质上还是在谈被打开文件和进程之间的关系从操作系统来看也就是进程pcb和struct file之间的关系

但是要注意:一个进程是可以打开多个文件的,就比如我们在代码中调用了多次的open接口,此时就可以同时打开很多个文件,所以进程和文件之间的关系不是1 :1,而是n :1

如下代码:

int fd1 = open(LOG1, O_WRONLY | O_CREAT, 0666);
int fd2 = open(LOG2, O_WRONLY | O_CREAT | O_TRUNC, 0666);
int fd3 = open(LOG3, O_WRONLY | O_APPEND | O_CREAT, 0666);
int fd4 = open(LOG4, O_RDONLY)

并且操作系统为了能够让进程快速的找到文件,所以操作系统内部是这样维护文件的:定义一个数据结构,struct file_struct,这个数据结构是一个数组结构,并且是一个指针数组,该数组中的数据是一个一个的 struct file*fd_array[] 的指针,这个结构体就是用来和上述的文件对象结构体struct file挂钩的,也就是用来存储这些文件对象的地址的,并且我们的进程pcb中还包含了一个struct files_struct*files;的一个结构体指针对象(本质上是因为,一个文件加载到内存,是先加载该文件对应的进程属性,也就是进程pcb,而不是加载代码和数据),并且需要通过该进程pcb快速的找到相应的文件对象

具体如下图所示
在这里插入图片描述
图例文字描述:
当从磁盘中加载一个文件到内存之时,操作系统根据先描述再组织,管理文件,为文件创建一个struct file对象,创建之后,因为这个打开的行为一定是某个进程让操作系统打开的,所以此时操作系统就会找到这个进程的pcb,在找到这个pcb的同时,会把内存中对应struct file对象的地址放到struct files_struct这个结构体数组为空的下标中,所以找到进程pcb后,操作系统就可以通过该进程pcb中的*files指针,找到该数组,进而找到某个下标对应的文件对象,然后把该数组对应的下标(也就是文件描述符)返回给进程的调用者(也就是用户),所以当我们打开一个文件,此时就肯定会对应着有一个文件描述符,也就是有一个数组下标,这也就是进程和被打开文件之间的关系导致的,进而通过进程(可执行文件),我们就可以对相应的文件进行操作了。

总:文件描述符的本质就是一个数组下标

感兴趣可以参考该链接:文件描述符详解

深入缓冲区

搞定了上述有关文件描述符的知识,此时我们就可以来看看和文件描述符息息相关的缓冲区的知识了,操作系统会将文件对象对应的缓冲区中的数据给刷新到外设中(磁盘),所以本质我们使用的write、read函数,都是拷贝函数,它们可以把我们想要写入的数据(字符串),给拷贝到文件对象对应的缓冲区中,并且注意:操作系统具体什么时候刷新缓冲区的数据是有操作系统自己决定的(例如:可以是在缓冲区中的数据满了再刷新,也可以是没满的时候,因为别的原因刷新,都是可能的),反正就是按照自己的刷新策略进行刷新,上述是写入到缓冲区的情况,读取本质上是同理的,但是是先找到在磁盘上的文件,然后把磁盘上的文件拷贝到对应的缓冲区中,然后再把该缓冲区的数据拷贝到我想要拷贝到的文件中(这个就是读取),本质还是通过缓冲区来完成的,所以下述让我们通过理解为什么一切皆文件,来深入了解缓冲区,如下:

如何理解一切皆文件:

首先我们要明白一个点,就是所有的外设你想要和它进行交互,也就是允许它供给我们的使用,那么这些外设就要有相应的读写方法,因为只有读写方法,我们才可以向该外设写入数据或者是向该外设读取数据,所以外设就为我们提供了相应的驱动程序,我们就可以通过相应的驱动程序来访问和使用对应的外设了,如下图所示:

在这里插入图片描述

所以在我们上述所说的一个文件被加载到内存时,此时这个文件对象中的众多属性中,就会包含一个有关读写数据的函数指针,通过这两个指针,就可以访问到相应的需要访问到的外设驱动程序上对应的读写函数,间接就可以调用相应的外设来帮我们完成文件中代码和数据需要的功能实现,所以此时我们就以我们的键盘(外设)为例,来看一看进程和被打开文件之间的关系到底是怎样的吧!

首先,我们创建了一个可执行文件,并且此时该文件中的代码和数据包含了调用系统接口open的代码,我们使用open去打开了一个在磁盘中安静睡觉的文件,此时操作系统就会帮我们去把该文件对应的部分数据和属性加载到内存,并且生成一个struct file的结构体对象来存储,并且会把该结构体对象的地址给给一个struct files_struct的顺序表类型结构体(目的:提高效率),并且此时这个结构体对象此时除了包含着该文件对应简单的属性之外,还有操作系统给与它的各种权限和功能,例如:可以通过结构体中的两个指针去访问任意外设的驱动程序上的有关读写函数(此时就可以将对应的数据拷贝到驱动程序之中),生成了struct file之后,此时我们自己的可执行文件(进程),操作系统为了管理这个进程,就会像管理文件一样,为该进程生成一个结构体 strcut task_struct,并且该结构体和struct file结构体一样,它其中不仅有该进程对应的部分属性,也有一个指针(struct files_struct* file),通过该指针,该进程就可以找到文件描述符表(就是一个存放各种文件对象的地址的数组),所以此时进程中的代码和数据中的open接口,就找到了对应的文件描述符表中的下标,也就是相应我们要打开的文件.

所以访问键盘的本质就是在通过一个文件对象中的函数指针访问键盘驱动程序中的读写函数,而我们的进程却只需要将对应文件中的代码和数据拷贝到相应的文件对象中的缓冲区就行,所以对于进程来说,它本质上只需要和被打开文件进行交互,剩下的向外设或者从外设写入和读取的操作,都只要交给文件对象(文件结构体)中的函数指针去完成就行了,所以对于进程来说,操作系统中的程序都是文件,因为它本质上只需要和文件对象进行交互,剩下和外设驱动程序之间的交互都只需要交给文件对象自己去完成就行了。

在这里插入图片描述

总结:今天踏实了许多,该博客也踏实了许多,很多知识掌握的还是比较扎实,所以慢就是快的理论还是很有道理的。

相关文章:

学习系统编程No.10【文件描述符】

引言&#xff1a; 北京时间&#xff1a;2023/3/25&#xff0c;昨天摆烂一天&#xff0c;今天再次坐牢7小时&#xff0c;难受尽在不言中&#xff0c;并且对于笔试题&#xff0c;还是非常的困难&#xff0c;可能是我做题不够多&#xff0c;也可能是没有好好的总结之前做过的一些…...

网络基础认识

目录 一、计算机网络背景 1.1 网络发展 1.2 "协议"由来 二、网络协议初识 2.1 协议分层 2.2 OSI七层模型 2.3 TCP/IP五层模型 三、网络协议栈 四、数据包封装与分用 五、网络传输基本流程 5.1 同局域网的两台主机通信 5.2 跨网络的两台主机通信 六、网络…...

【蓝桥杯_练习】

蓝桥杯1.创建工程2.LED灯点亮led.c3.LCD液晶屏显示lcd.c4.定时器按键单机interrupt.hinterrupt.cman.c5.定时器&#xff08;长按键&#xff09;interrupt.hinterrupt.cmain.c6.PWMmain.c7.定时器-输入捕获&#xff08;频率&#xff0c;占空比测量&#xff09;interrupt.cmain.c…...

【C语言蓝桥杯每日一题】——跑步锻炼

【C语言蓝桥杯每日一题】—— 跑步锻炼&#x1f60e;前言&#x1f64c;排序&#x1f64c;总结撒花&#x1f49e;&#x1f60e;博客昵称&#xff1a;博客小梦 &#x1f60a;最喜欢的座右铭&#xff1a;全神贯注的上吧&#xff01;&#xff01;&#xff01; &#x1f60a;作者简介…...

Qt之实现类似软件安装时的新功能介绍界面

一.效果 在软件安装时,一般会轮播软件的新功能,安装后,如果还想查看这些新功能该怎么办呢,我们可以把这个介绍新新功能的小应用集成到软件的“帮助”菜单中,比起纯黑文字的无趣介绍,图文方式的呈现会生动得多。 最近在看《赘婿》,借几张图过来用用。 二.原理 1.分层结…...

echarts地图不同地区设置不同的颜色

var myChart ec.init(document.getElementById(main));let option {tooltip: {trigger: item,},dataRange: {//左下角的颜色块。start&#xff1a;值域开始值&#xff1b;end&#xff1a;值域结束值&#xff1b;label&#xff1a;图例名称&#xff1b;color&#xff1a;自定义…...

网易云音乐API部署Vercel获取接口过程

前提&#xff1a;部署自己的网易云接口主要用途在于在完成前端的仿网易云播放器的时候&#xff0c;根据自己部署的接口可以用于获取数据。大体流程是通过在github上fork别人的API接口项目&#xff0c;然后在Vercel部署即可获得自己的网易云后端数据接口了&#xff0c;不过根据我…...

Java基础:字符串(String)及常用操作

目录 字符串的声明及创建 字符串的操作 连接字符串&#xff08;或concat&#xff09; 获取字符串的长度 length 查找字符串 indexOf 获取字符串某个位置的字符 charAt 查询某个字符串是否存在 contains 截取字符串 substring&#xff08;一&#xff09; 截取字符串 su…...

FL Studio 21中文版支持主题随心换,FL Studio 21Mac版新增对苹果M2/1家族芯片原生支持。

FL Studio 21.0.0 官方中文版重磅发布 纯正简体中文支持&#xff0c;更快捷的音频剪辑及素材管理器&#xff0c;多样主题随心换&#xff01; Mac版新增对苹果M2/1家族芯片原生支持。 更新版本&#xff1a;21.0.0支持语言&#xff1a;简体中文/英语更新时间&#xff1a;2022.12…...

【蓝桥杯集训·周赛】AcWing 第96场周赛

文章目录第一题 AcWing 4876. 完美数一、题目1、原题链接2、题目描述二、解题报告1、思路分析2、时间复杂度3、代码详解第二题 AcWing 4877. 最大价值一、题目1、原题链接2、题目描述二、解题报告1、思路分析2、时间复杂度3、代码详解第三题 AcWing 4878. 维护数组一、题目1、原…...

【数据结构】顺序表的深度刨剖析

前言&#xff1a;在上一篇文章中&#xff0c;我们已经对数据结构有了一定了解&#xff0c;我们可以通过优化空间复杂度或者时间复杂度从而提高我们程序运行或存储速率。至此我们就知道了数据结构的重要性&#xff0c;所以今天我们将要了解和学习一种实用的数据结构——线性表。…...

Unity 之 使用原生UGUI实现随手移动摇杆功能经典实例

Unity 之 使用原生UGUI实现随手移动摇杆功能实现效果一&#xff0c;实现思路1.1 原理解析1.2 思路概述二&#xff0c;实现代码2.1 随手落下2.2 摇杆转动三&#xff0c;源码分享3.1 场景搭建3.2 完整代码3.3 实现效果实现效果 本文最终实现效果&#xff1a; 一&#xff0c;实现…...

Linux内核源代码概述

Linux内核源代码非常庞大&#xff0c;截止到2015年据统计代码总量就已经超过1500万行&#xff08;LOC&#xff0c;Line of Code&#xff09;&#xff0c;看代码总量非常吓人&#xff0c;具体看这1500万行代码的大致分布情况如下图。 显然占比最大的drivers和arch目录下的代码合…...

Nginx 教程-动静分离

一、Nginx 动静分离理论1、概念今天学习和梳理Nginx动静分离&#xff0c;动静分离是将网站静态资源&#xff08;HTML&#xff0c;JavaScript&#xff0c;CSS&#xff0c;img等文件&#xff09;与后台应用分开部署&#xff0c;之所以要进行动静分离&#xff0c;其一为了提高前端…...

自己设计的网站,如何实现分页功能?(详细代码+注释)

目录 前言 实现分页功能 需求分析 客户端开发 服务器开发 前后端交互——两种前端得到 文章总页数 的方法&#xff0c;那种更合适&#xff1f; 前言 你在设计网站的时候是否有过这样的烦恼&#xff1a;“我设计的网站怎么就是从上到下一条线内容全部展开&#xff0c;一点都…...

STM32F407控制微型推拉式电磁铁(通过继电器)

1、继电器 继电器相当于开关&#xff0c;单片机通过io口高低电平的控制来控制继电器的开闭。采用继电器的好处除了能够用低电压控制高电压&#xff08;如32单片机控制220V的电压&#xff09;外&#xff0c;还可以防止电流反冲&#xff0c;弄烧单片机。 本文采用3.3v的电磁铁&am…...

VS Code工作区用法

背景VS Code可以通过"文件/打开文件夹"来打开本地项目&#xff0c;但是想要打开多个项目便需要来回切换&#xff0c;比较费劲。此时就可以使用工作区功能&#xff0c;将不同的项目放置到同一个工作区中&#xff0c;这样切换项目的时候就会非常方便。操作方法打开其中…...

Mybatis-Plus SQLFeatureNotSupportedException: getObject with type问题解决

问题描述&#xff1a; Error attempting to get column modify_time from result set. Cause: java.sql.SQLFeatureNotSupportedException: getObject with type ; getObject with type; nested exception is java.sql.SQLFeatureNotSupportedException: getObject with type…...

Unity | 发布Android的那些事儿

1.使用UnityWebRequest获取StreamingAssets中的json文件&#xff08;1&#xff09;直接根据不同平台指定url路径IEnumerator AITalPredZhanHui(){string url;string fileName "girl.json"; #if UNITY_EDITOR || UNITY_STANDALONEurl "file://" Applicat…...

git为什么要先commit,然后pull,最后再push?而不是commit完直接push?

情况是这样的&#xff0c;现在远程有一个仓库&#xff0c;分支就一个&#xff0c;是master。然后我本地的仓库是从远程的master上clone下来的。大家都是clone下来&#xff0c;再在自己本地改好&#xff0c;再commit然后pull然后push&#xff0c;大家都是这么做的。那么现在问题…...

若依框架----源码分析(@RateLimiter)

若依作为最近非常火的脚手架&#xff0c;分析它的源码&#xff0c;不仅可以更好的使用它&#xff0c;在出错时及时定位&#xff0c;也可以在需要个性化功能时轻车熟路的修改它以满足我们自己的需求&#xff0c;同时也可以学习人家解决问题的思路&#xff0c;提升自己的技术水平…...

页面的重排和重绘?

思路&#xff1a; 网页渲染HTML文件到浏览器的过程->定义->如何优化网页渲染HTML文件到浏览器的过程HTML 文件通过HTML解析器解析生成DOM树&#xff1b;CSS文件通过CSS解析器生成CSSOM树&#xff1b;DOM树和CSSOM树生成渲染树&#xff08;render tree&#xff09;&#x…...

人脸检测-python和c++实现

人脸检测是计算机视觉领域中的一个重要应用,其目的是从图像或视频中自动检测出其中的人脸,并对其进行识别、跟踪等操作。人脸检测技术已经广泛应用于安防、人机交互、娱乐等领域,具有广泛的应用前景。 人脸检测的基本思路可以分为以下几个步骤: 图像预处理:首先需要对输入…...

PowerJob源码环境搭建

一、IEDA导入PowerJob源码 gitgithub.com:PowerJob/PowerJob.gitPowerJob 由调度服务器&#xff08;powerjob-server&#xff09;和执行器&#xff08;powerjob-worker&#xff09;两部分组成 powerjob-server 负责提供 Web 服务和完成任务的调度powerjob-worker 则负责执行用…...

天梯赛刷题小记 —— L2

最近在重刷 天梯赛&#xff0c;浅浅记录一下&#xff0c;进入L2阶段了 L2-001 紧急救援 解题思路&#xff1a;典型的dijkstra模板题&#xff0c;带路径记录与权重&#xff0c;方案数记录&#xff0c;解析出过 Dijkstra(兼路径) #include <bits/stdc.h> #define inf…...

Prometheus监控实战系列十九:监控Kubernetes集群(上)

Kuberentes是一款开源的容器编排产品&#xff0c;由Google开发后发布到社区&#xff0c;并在2015年将该项目捐献给了云原生基金会&#xff08;Cloud Native Computing Foundation&#xff09;。从2014年第一个版本发布以来&#xff0c;Kubernetes便迅速获得开源社区的追捧&…...

番茄学习法——亲测超级好用

今天给大家分享下我最近使用的学习方法&#xff0c;真的非常好用&#xff01;大家用起来&#xff01; 在日常的学习和工作中&#xff0c;我们经常会遇到一些难以克服的问题&#xff1a;分心、效率低下、焦虑等。为了帮助人们更好地学习和工作&#xff0c;一些学习方法和工具应运…...

vue 项目中使用高德地图

一、账号准备 首先&#xff0c;需要注册并登录高德地图开放平台&#xff0c;申请密钥。操作指引&#xff1a;高德地图开放平台 二、安装高德地图加载器 npm 安装&#xff1a; npm i amap/amap-jsapi-loader --save或者 yarn 安装&#xff1a; yarn add amap/amap-jsapi-loa…...

【每日一题】病人排队

题目描述小理是个热爱生活的孩子。病人登记看病&#xff0c;小理想编写一个程序&#xff0c;将登记的病人按照以下原则排出看病的先后顺序&#xff1a;1. 老年人&#xff08;年龄 ≥≥ 60岁&#xff09;比非老年人优先看病。2. 老年人按年龄从大到小的顺序看病&#xff0c;年龄…...

【数据结构】链表OJ题

目录面试题 02.04 分割链表剑指 Offer II 027 回文链表160 相交链表141 环形链表142 环形链表 II138 复制带随机指针的链表面试题 02.04 分割链表 定义lesshead和greaterhead链接小于和大于等于k的值分别设置哨兵位和尾节点指针最后将两表去除哨兵位再链接 struct ListNode* p…...