Linux下的第一个程序——进度条(命令行版本)

文章目录

  • 编写Linux下的第一个小程序——进度条
    • 进度条的样式
    • 前置知识
      • 回车和换行
      • 缓冲区
      • 对回车、换行、缓冲区、输出的测试代码
        • 简单的测试样例
        • 倒计时程序
    • 进度条程序
      • 理论版本
        • 基本框架
        • 代码实现
      • 真实版本
        • 基础框架
      • 代码实现

编写Linux下的第一个小程序——进度条

在前面的基础开发工具的学习中,我们学习了几个比较重要的开发工具。
当然,对于在开发过程中常用的工具是gcc/g++、vim、make,有了这三个工具的基础后,我们就可以尝试着写一个在Linux系统下开发的小项目了。

而本篇文章将讲解在Linux系统下开发的小程序——进度条。

进度条的样式

在这里,我们得明确进度条的样式。有了进度条的样式之后,我们才好根据我们要求的样式进行相对应的程序包编写。

在这里插入图片描述
进度条在命令行上的样式大致就是这个样子,但是对于进度条而言,需要特别注意的是:
1.旋转光标应当一直在旋转,以表明当前进度仍在进行(只不过某段时间内进度为0)
2.百分比应该动态的增大
3.进度条展示的位置应该是有东西不断地再填充中间的空位,从肉眼上看的效果就是进度条再动态的前进,其实背后是显示屏在不断地刷新和字符不断地填充输出而已。

基于上述的原理,我们就可与依次来编写对应的程序。

前置知识

但是,当前我们还得再补充一些基础的知识,这是针对于IO流的输入和输出的问题。

回车和换行

首先,我们来重新了解一下回车和换行。

在我们以往的认知中,我们会很自然地认为”回车“和”换行“是同一件事情。其实不是的。
在这里插入图片描述
就以我们写作文的作文格子来举例,如上图所示
单纯的换行是把笔尖直接置到同一列的下一行的位置。
单纯的回车是把笔尖置到这一行的第一个开头位置。
回车换行先把笔尖置于开头后再进行换行。

这也很清楚的说明,换行和回车其实不是一样的操作。但是为什么在c/c++程序里面,打印‘\n’确实出现了回车 + 换行的操作呢?
这是因为编译器自行解析了,编译器在碰到换行符的时候,会解析成“回车 + 换行”。

在c/c++程序中,换行符是‘\n’,回车符是‘\r’
c/c++碰到‘\n’会自动解析成‘\r’ + ‘\n’

缓冲区

这个概念其实早在c语言学习的时候就讲到过了,但是我们这里还是再进行一次复习,以便后面顺利编写进度条的代码。

我们来看看下面这一个代码:

#include<stdio.h>
#include<unistd.h>int main(){printf("Hello World");sleep(3);return 0;
}

我们来看看这个代码的输出结果:

在这里插入图片描述
暂停了三秒钟…
在这里插入图片描述
我们会发现,显示器上会暂停三秒钟,也就是在这三秒钟内是没有任何的输出的。但是三秒后,Hello World就被输出在了显示器上,但是没有换行效果。

可是我们学过c/c++程序的代码执行顺序,是从上往下执行的。也就是说,printf函数必然是比sleep函数先执行的。那么printf执行后,打印的内容放在哪里呢?答案就是缓冲区。

其实我们之前讲过,Linux下一切皆为文件。即使是我们的显示器(FILE* stdout)。printf是先把内容输出到缓冲区的。缓冲区再输出到显示器上是执行行刷新原则,即碰到换行符才会把内容给输出到标准输出流这个显示器文件上。

上面那一段代码就是先把Hello World写入缓冲区,但是又没碰到换行符。所以就没有办法先把字符串输出到显示器上。
但是后面能打印出来的原因是——程序结束后会自动刷新缓冲区,所以内容就会被输出了。


当然,如果我们想要自行刷新缓冲区从而输出字符串也是可以的,可以使用函数fflush,我们可以对stdout进行刷新(fflush(stdout))
在这里插入图片描述
此时我们就可以发现,字符串先打印出来到显示器了,然后再进行休眠。

对回车、换行、缓冲区、输出的测试代码

在写进度条项目之前,我们还是需要进行一些前置准备——测试代码。

我们上面仅仅是理论上讲解了回车、换行、缓冲区的知识,这些其实和系统层面是有关系的。我们以前很多时候写的程序是停留在语法层面上的。所以对系统层面上的一些内容不是很清楚。在这里我们需要进行相关功能的测试,结合对输出的理解,这样子后面写进度条这个小项目的时候写起来就快很多了。

简单的测试样例

我们下面看第一个测试代码:

#include<stdio.h>
#include<unistd.h>
int main(){printf("%d\r", 1235456);fflush(stdout);sleep(3);printf("%s\n", "xx123456");return 0;
}

我们来看看这个代码,最后的输出效果是怎么样的:

在这里插入图片描述
在这里插入图片描述
我们会发现,这里会先打印出123456这个数字,停留三秒后,由于回车符的作用,光标会重新放在开头处,然后再次打印字符串”xx123456“的时候就会把原先打印的字符给覆盖掉。

所以这里的输出效果是,先在一行中打印数字123456,停留三秒后,打印字符串”xx123456“,覆盖掉原来的123456,最后输出结束。

这个代码结合了回车、换行、缓冲区的知识,能够更好地帮助我们理解这些内容。


倒计时程序

上面的测试代码已经初步地了解和掌握了换行、回车、缓冲区的一些相关的用法。但是还有一些问题是我们在写进度条的代码的时候会遇见的。

这些问题其实在这个简单地倒计时程序里就可以体现出来,接下来我们一起来看一下:

初版代码:

#include<stdio.h>int main(){int i = 9;while(i >= 0){printf("%d\n", i);--i;}return 0;
}

这个代码费城非常简单,在这里就不多说了。就是输出倒计时9 ~ 0,只不过是会换行输出。这里写这个代码的是为了和后面的改进版本进行对比:
在这里插入图片描述
但是我们想要的倒计时不是这个样子的,我们希望的是,每次屏幕上闪动动一个数字,一秒后在相同的位置变成下一秒的数字,那这个时候该怎么办?

版本二:
这个不久正好用到了上个部分测试样例中用到的原理吗?我们使用回车符就可以了,然后每次控制打印的数字的显示时间即可:

#include<stdio.h>
#include<unistd.h>int main(){int i = 9;while(i >= 0){printf("%d\r", i);sleep(1);--i;}return 0;
}

在这里插入图片描述
但是我们发现一个问题,就是不打印。这个其实就是没有刷新缓冲区的原因:
在这里插入图片描述

在这里插入图片描述
添加了刷新缓冲区的代码后,我们发现,打印完最后一个数字0后被命令行覆盖掉了。因为命令行的前面这一串内容也可以看作是字符串,但是我们刚刚输出的数字倒计时没有进行换行,所以最后命令行字符串打印的时候直接覆盖掉了,所以我们可以自行添加一个换行符:

#include<stdio.h>
#include<unistd.h>int main(){int i = 9;while(i >= 0){printf("%d\r", i);fflush(stdout);sleep(1);--i;}printf("\n");return 0;
}

在这里插入图片描述


上面的代码看似没有问题,但其实还有一些小问题没有解决,比如我们把i改成10看看:
在这里插入图片描述
我们会发现,打印完10之后,剩下的数字都会打印在开头的位置,但是末尾会有一个0出现。

这个原因其实很简单,只是我们得明白一个原理:
所谓的打印,其实就是打印字符!

我们将123456打印在显示器上,其实并不是把数字打印在上面,而是把123456字符打印在了显示器上而已。所以 这里也是一样的道理。10是两个字符,但是0 ~ 9是一个字符,所以10正常输出后,剩下的0 ~ 9因为回车符\r的原因,会在行开头位置打印,但是因为占位是1个字符,所以后面那个0没办法被覆盖掉。

解决办法很简单,改一下printf函数的打印格式就好了:
在这里插入图片描述
打印的时候在占位符前面加一个数字2,表示一次性打印的字符位宽为2(这个数字取决于倒计数里面最大的那个的数位),不足的就填充。但是这样子我们会发现,个位数打印的时候左边是空的,这非常不美观。

所以这就用需要用到我们在printf函数中学到的“左对齐”打印了:

最终版本:

#include<stdio.h>
#include<unistd.h>int main(){int i = 10;while(i >= 0){printf("%-2d\r", i);fflush(stdout);sleep(1);--i;}printf("\n");return 0;
}

printf函数默认是右对齐的,所以字符不够的时候前面会被填充。所以这里我们可以在数字的前面加一个-,这样子就会左对齐了:
在这里插入图片描述
至此,我们就完成了倒计时程序的编写。

同时,我们还进一步地用实践来验证了一我们前面所讲的一些前置知识,有了这些前置知识,我们就可以更好地去编写我们对应的进度条程序了。

进度条程序

这个部分我们将一起来编写进度条的程序,就按照我们在前面提及的样式进行编写。

在这里我们会给出两个版本:理论版本和真实版本。
理论版本就是我们现在只负责写进度条的变动逻辑。两个版本的差异呢?这是因为理论版本只写了进度条的变动逻辑,但是进度条这个东西一般都是配合一些任务进行的,进度跳的逻辑应该是穿插在某些程序的内部的。

所以由此得知,理论版本的进度条其实是没办法运行的,就只能作为进度条的跳动的理论展示而已,所以我们会分开两个版本进行编写。

但是写出来理论版本就好办多了,因为真实版本也就是把进度条的逻辑嵌套在其他的代码中。

理论版本

我们先来看理论版本的代码。

基本框架

我们需要四个文件:

Process.h 包含进度条代码需要用到的头文件、变量、声名进度条展示函数
Process.c 定义进度条展示的函数
main.c 对编写的进度条代码进行测试
Makefile 进行自动化编译

对于Makefile的编写,其实我们早就学习过了。
而且我们在Makefile的学习中,我们把对应的Makefile的形式改的更加通用,所以我们只需要修改一下文件中的部分文件名即可:

//Makefile
BIN=Process.exe 
SRC=$(wildcard *.c)
OBJ=$(SRC:.c=.o);
FFLAG=-o
FLAG=-c
RM=rm -rf$(BIN):$(OBJ)gcc $(FFLAG) $@ $^
%.o:%.cgcc $(FLAG) $<.PHONY:clean 
clean:$(RM) $(BIN) $(OBJ)

其实最后我们发现也就是修改了一下生成的可执行文件而已。

接下来是项目的主体框架:

//Process.h
#pragma once 
#include<stdio.h>
#include<unistd.h>
#include<string.h>#define Num 101
#define STYLE '='void Process();//Process.c
#include"Process.h"void Process(){}//main.c
#include"Process.h"int main(){Process();return 0;
}
代码实现

首先,我们得知道进度条的变动的原理,其实就是打印一个字符数组。那是如何做到进度条的前进的呢?

其实就是不断地打印这个进度条,把上一次的进度给覆盖掉,每次打印的进度条里面需要填充更多的符号以表示进度跳动而已。

我们在这里先看代码,然后再详细解释:

void Process(){char buffer[Num];memset(buffer, 0, sizeof(buffer));int i = 0;char lable[] = "/-|\\";int length = strlen(lable);while(i <= 100){printf("[%-100s][%d%%][%c]\r", buffer, i, lable[i % length]);fflush(stdout);buffer[i] = STYLE;usleep(10000);++i;}printf("\n");
}

首先,我们确定了进度条的最大百分比是100%,所以需要100个空间打印字符(表示进度),这些字符是放在一个char数组内的,本质就是字符串。打印的时候需要碰到\0才会停止,所以存储进度条字符的数组是需要101个空间的,所以Num的值为101。

而且我们把buffer这个数组中的所有值初始化为\0,这样子后面我们就不需要再处理字符串的\0问题了。

在这个理论版本,我们就假设进度条每次进度+1%,所以打印百分比很简单,就是打印我们定义的计数器i。

当然,我们还需要设置一个旋转光标,以表示当前进度还在继续,只不过是进度很慢而已,所以需要一直旋转光标。光标的旋转其实也是字符的快速打印,把中间间隙去掉,在我们的肉眼来看其实就是旋转的效果,所以定义了一个label数组,里面就是光标旋转的时候可能会有图案。但是这里要注意的,由于 \ 这个字符本身在c/c++程序中有转义字符的意思,所以要想打印出 \ ,需要对其再加一层 \ 的转义。
对于光标的打印,其实就是不断地打印label数组中的字符,但是不能越界访问label数组,所以需要对坐标进行取模运算。

然后每次打印完进度条后,就应该改动进度条,以便下一次的打印。在这个理论版本中,就是不断地往这个数组内部填充字符。

还有一个点就是,由于在printf函数中%是被赋予了特殊意义,所以只写一个%是打印不出来的,要想打印出来%就需要写两个。

当然上面还有一些细节我没有讲到,但其实都是在前面的前置知识中有说过的。所以在这里就不再过多的赘述了。

最后,我们来看几张效果图:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

这里就随意的选取几张图看看,感兴趣的可以自行拷贝实验一下。

真实版本

前面是理论版本,也就是我们完成了进度条的动态操作。但是这个程序一般都是放在一些下载/上传等场景下配合使用的。所以这个部分我们就来模拟一下下载场景。

基础框架

还是一样,我们需要准备四个文件:

ProcessBar.h 包含进度条代码需要用到的头文件、变量、声名进度条展示函数
ProcessBar.c 定义进度条展示的函数
main.c 定义下载函数和其相关变量
Makefile 进行自动化编译

有了前面的基础,这里就不过多的废话了:

//Makefile
BIN=Load.exe 
SRC=$(wildcard *.c)
OBJ=$(SRC:.c=.o);
FFLAG=-o
FLAG=-c
RM=rm -rf$(BIN):$(OBJ)gcc $(FFLAG) $@ $^
%.o:%.cgcc $(FLAG) $<.PHONY:clean 
clean:$(RM) $(BIN) $(OBJ)
//main.c
//使用随机数来模拟每次下载的量 需要用到下面两个头文件
#include<stdlib.h>
#include<time.h>
#include"ProcessBar.h"
#define TOTAL 1024.0//总的下载量void Download(){}int main(){Download();return 0;
}//ProcessBar.h
#pragma once #include<unistd.h>
#include<string.h>
#include<stdio.h>
#define Num 101
#define STYLE '='static int lable_move = 0;//用于光标数组的坐标void Process(int cur, double total);//进度条函数//ProcessBar.c
#include"ProcessBar.h"void Process(int cur, double total){}

但是这里需要稍微解释一下,这里的进度条打印函数相比理论版本是多了两个参数的。即当前下载的量cur和总共要下载的量total

因为当前这里的进度条函数是嵌套在下载函数Download当中的,但是进度条最终的是什么?是进度。进度是需要计算的。这里的进度条需要展示下载的进度,所以需要获取到当前下载的量和总共要下载的量,以便能够在内部进行计算。所以这里需要传入两个参数。

代码实现

接下来我们将对代码的实现进行讲解。

首先我们得明白,在真实版本下的进度条,我们是不需要想理论版本那样,去进行屏幕沉睡(sleep函数)的控制,也不需要我们自己去计算下一次的进度。因为这些事情都是下载函数Download去操作的。
换而言之:Process函数只负责接收当前的进度和总任务量,进行进度的计算,然后根据计算量去显示进度条即可!

这里我们也是先直接展示代码:

//main.c
#include<stdlib.h>
#include<time.h>
#include"ProcessBar.h"
#define TOTAL 1024.0void Download(){srand((unsigned int)time(NULL));int speed = rand()%10;//0 ~ 9int cur_load = 0;while(cur_load <= TOTAL){//打印进度条Process(cur_load, TOTAL);usleep(20000);//sleep(1);// if(cur_load == TOTAL){printf("\n");return;}//重新计算下载量cur_load += speed;if(cur_load > TOTAL) cur_load = TOTAL;speed = rand()%10;}
}int main(){Download();return 0;
}//ProcessBar.h
#pragma once #include<unistd.h>
#include<string.h>
#include<stdio.h>
#define Num 101
#define STYLE '='static int lable_move = 0;void Process(int cur, double total);//ProcessBar.c
#include"ProcessBar.h"void Process(int cur, double total){char buffer[Num];memset(buffer, 0, sizeof(buffer));char lable[] = "/|-\\";int length = strlen(lable);double Precent = (cur * 100 / total);int i = 0;for(i = 0; i < (int)(Precent); ++i){buffer[i] = STYLE;} printf("[%-100s][%.2lf%%][%c]\r", buffer, Precent, lable[lable_move]);fflush(stdout);++lable_move;lable_move %= length;
}

我们下面来解释一下上述代码的逻辑:

首先对于main.c来说,其实就是写一个Download的下载函数,然后main函数中调用一下即可。但是这里我采用了随机数的方式来获取每次的下载量(speed),让下载量有所不同。

但是这里就需要注意一个问题了,很有可能某一次打印完进度条后,再接收下载量可能就超过TOTAL了,这样子下一次就不会进入循环了。但其实还是有最后一小部分的进度是没有显现出来的。所以当下载量speed大于剩余可以下载的量时候,就需要调整speed大小。然后为了能够进入循环,所以循环条件内,下载量cur_load是需要可以等于TOTAL的。
但是又因为我们对下载量进行特殊处理,如果我们打印完进度条(Process函数)后,不进行判断,就会导致死循环(因为剩余下载量0 <= speed)。所以这里的循环其实是内部进行退出的。不这么写会导致死循环的。
然后就是退出循环的时候,需要打印一个换行符,这样子才能使得进度条单独成一行。


然后就是Process函数的处理,其实就是修改一下理论版本的进度条函数就可以了。
只不过就是我们需要自行的计算进度,然后把进度对应的字符数填入数组后再打印数组。

但是这里还有一点是不一样的,就是光标的旋转。前面写理论版本的时候我是偷了一个懒,直接拿计数器取余i就获得了label数组的下标了。

但其实这样子不对,光标应该是有一个它自己的独立的坐标数的,即使有时候进度条进度增加为0%,但是它也应该在转,这表示当前进度仍在进行。如果写成理论版本那样就是进度增加为0%的时候光标是不转的。只不过理论版本的计数器i一直在变,所以光标也会一直转。

所以这里需要一个计数器,每次打印进度条就获取对应位置中label数组的元素。但是这里是需要使用一个静态变量的。因为静态变量存储在静态区,每次++后是会被保存下来这个状态的。如果是使用栈区上的局部变量,那每次进来都是重新初始化的,这不符合要求。然后再注意这个坐标不要越界即可。

最后,我们还是来看几张效果图:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述这里也是随机截的几张图,我们发现确实是我们想要的结果。

至此,我们所有的关于进度条的内容就讲完了。

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

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

相关文章

【项目】仿muduo库one thread one loop式并发服务器前置知识准备

&#x1f4da; 博主的专栏 &#x1f427; Linux | &#x1f5a5;️ C | &#x1f4ca; 数据结构 | &#x1f4a1;C 算法 | &#x1f152; C 语言 | &#x1f310; 计算机网络 |&#x1f5c3;️ mysql 本文介绍了一种基于muduo库实现的主从Reactor模型高并发服务器框架…

steam报网络错误,但电脑是网络连接的

steam报网络错误&#xff0c;但电脑是网络连接的 如&#xff1a; 解决办法&#xff1a; 关闭电脑防火墙和所有杀毒软件&#xff0c;然后重新打开steam开代理&#xff0c;可能国内有时候访问不了 首选1进行尝试 steam安装路径一定要在纯英文路径下 已ok

Vue 组合式 API 与 选项式 API 全面对比教程

一、前言&#xff1a;Vue 的两种 API 风格 Vue 提供了两种编写组件逻辑的方式&#xff1a;组合式 API (Composition API) 和 选项式 API (Options API)。理解这两种方式的区别和适用场景&#xff0c;对于 Vue 开发者至关重要。 为什么会有两种 API&#xff1f; 选项式 API&a…

HarmonyOS 应用模块化设计 - 面试核心知识点

HarmonyOS 应用模块化设计 - 面试核心知识点 在 HarmonyOS 开发面试中&#xff0c;模块化设计是必考知识点。本文从面试官角度深度解析 HarmonyOS 应用模块化设计&#xff0c;涵盖 HAP、HAR、HSP 等核心概念&#xff0c;助你轻松应对技术面试&#xff01; &#x1f3af; 面试高…

Maven高级学习笔记

分模块设计 为什么分模块设计?将项目按照功能拆分成若干个子模块&#xff0c;方便项目的管理维护、扩展&#xff0c;也方便模块间的相互调用&#xff0c;资源共享。 注意事项&#xff1a;分模块开发需要先针对模块功能进行设计&#xff0c;再进行编码。不会先将工程开发完毕&…

[创业之路-423]:经济学 - 大国竞争格局下的多维博弈与科技核心地位

在当今风云变幻的国际舞台上&#xff0c;大国竞争已成为时代的主旋律&#xff0c;其激烈程度与复杂性远超以往。这场全方位的较量&#xff0c;涵盖了制度、思想、文化、经济、科技、军事等诸多关键领域&#xff0c;每一个维度都深刻影响着大国的兴衰成败&#xff0c;而科技在其…

【企业容灾灾备系统规划】

一、企业灾备体系 1.1 灾备体系 灾备切换的困境: 容灾领域的标准化方法和流程、算法体系是确保业务连续性和数据可靠性的核心,以下从标准框架、流程规范、算法体系三个维度进行系统分析: 1.1.1、标准化方法体系​ ​1. 容灾等级标准​ ​国际标准SHARE78​: 将容灾能力划…

Kafka Connect基础入门与核心概念

一、Kafka Connect是什么&#xff1f; Apache Kafka Connect是Kafka生态中用于构建可扩展、可靠的数据集成管道的组件&#xff0c;它允许用户将数据从外部系统&#xff08;如数据库、文件系统、API等&#xff09;导入Kafka&#xff08;Source Connector&#xff09;&#xff0…

从零手写Java版本的LSM Tree (四):SSTable 磁盘存储

&#x1f525; 推荐一个高质量的Java LSM Tree开源项目&#xff01; https://github.com/brianxiadong/java-lsm-tree java-lsm-tree 是一个从零实现的Log-Structured Merge Tree&#xff0c;专为高并发写入场景设计。 核心亮点&#xff1a; ⚡ 极致性能&#xff1a;写入速度超…

Kotlin的5个主要作用域函数

applay, also,let, run, with 是kotlin标准库提供的5个主要的作用域函数&#xff08;Scope Functions&#xff09;​&#xff0c;它们的设计目的是为了在特定作用域内更简洁地操作对象。 如何使用这5个函数&#xff0c;要从它的设计目的来区分&#xff1a; apply : 配置/对象…

原型模式Prototype Pattern

模式定义 用原型实例指定创建对象的种类&#xff0c;并且通过复制这些原型创建新的对象&#xff0c;其允许一个对象再创建 另外一个可定制的对象&#xff0c;无须知道任何创建的细节 对象创建型模式 基本工作原理是通过将一个原型对象传给那个要发动创建的对象&#xff0c;这…

基于深度学习的智能交通流量预测系统:技术与实践

前言 随着城市化进程的加速&#xff0c;交通拥堵问题日益严重&#xff0c;给人们的日常生活和经济发展带来了巨大的挑战。智能交通系统&#xff08;ITS&#xff09;作为解决交通问题的重要手段&#xff0c;逐渐成为研究的热点。其中&#xff0c;交通流量预测是智能交通系统中的…

Cilium动手实验室: 精通之旅---23.Advanced Gateway API Use Cases

Cilium动手实验室: 精通之旅---23.Advanced Gateway API Use Cases 1. Lab说明1.1 高级网关 API 使用案例 2. 负载均衡器2.1 部署应用程序2.2 部署 Gateway 和 HTTPRoute 3. HTTP 标头请求修饰符3.1 部署 HTTPRoute3.2 可观测性 4. HTTP 响应标头重写5. HTTP 流量镜像5.1 demo应…

Agentic Workflow是什么?Agentic Workflow会成为下一个AI风口吗?

无论是想要学习人工智能当做主业营收&#xff0c;还是像我一样作为开发工程师但依然要运用这个颠覆开发的时代宠儿&#xff0c;都有必要了解、学习一下人工智能。 近期发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;入行门槛低&#x…

Some chunks are larger than 500 KiB after minification. Consider

在 vue3vite 项目开发中&#xff0c;build 打包时出现以下警告报错&#xff1a; (!) Some chunks are larger than 500 KiB after minification. Consider: - Using dynamic import() to code-split the application - Use build.rollupOptions.output.manualChunks to improve…

NodeJS11和10以及之前的版本,关键差异?

Node.js 11 相比 10&#xff08;及更早版本&#xff09;&#xff0c;除了事件循环行为的重大改变&#xff0c;还有多个核心模块和底层机制的升级。以下是它们的关键差异和新特性对比&#xff0c;帮助你快速掌握两个版本的重要变化。 &#x1f527; 一、事件循环行为变化&#x…

调和级数 敛散性

调和级数的敛散性是一个非常经典的问题。我们来全面分析它。 &#x1f9e0; 调和级数定义 调和级数是指&#xff1a; ∑ n 1 ∞ 1 n 1 1 2 1 3 1 4 ⋯ \sum_{n1}^{\infty} \frac{1}{n} 1 \frac{1}{2} \frac{1}{3} \frac{1}{4} \cdots n1∑∞​n1​121​31​41​⋯ …

Python•元组集合字符串

ʕ⸝⸝⸝˙Ⱉ˙ʔ ♡ 元组&#x1f6e5;️创建访问修改解包其他操作比较的依据 集合&#x1f6f8;创建添加和删除其他操作 字符串&#x1fa82;创建索引和切片基本操作连接加号join() 重复查找in 关键字index()find()startswith()endswith() ​​替换​​分割​​大小写删除 能…

​​信息系统项目管理师-项目整合管理 知识点总结与例题分析​​

​​一、项目整合管理概述​​ ​​1. 定义与重要性​​ 项目整合管理是项目管理知识领域中的核心过程,它协调所有其他知识领域的过程和活动,确保项目各要素有效整合。其核心目标是: ​​统一项目目标​​:确保各要素服务于共同目标​​协调冲突​​:解决项目执行中的各…

『uniapp』onThemeChange监听主题样式,动态主题不正确生效,样式被覆盖的坑

目录 问题示例代码解决思路1&#xff08;缺点影响显示效果有延迟&#xff09;解决思路2——通过路由刷新页面&#xff08;缺点只适用于部分网页&#xff09;解决思路3——vuex&#xff08;没学会~&#xff09;总结 欢迎关注 『uniapp』 专栏&#xff0c;持续更新中 欢迎关注 『…