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

【Linux 学习计划】-- 倒计时、进度条小程序

目录

\r 、\n、fflush

倒计时

进度条

进度条进阶版

结语


\r 、\n、fflush

首先我们先来认识这三个东西,这将会是我们接下来两个小程序的重点之一

首先是我们的老演员\n,也就是回车加换行

这里面其实包含了两个操作,一个叫做回车,一个叫做换行

而单纯的回车就是指,我们现在的光标,回到当前行的最前面

而换行 + 回车就是来到下一行的最前面

而我们的 \r 就是单纯的回车,回到当前行的最前面

但是我们还有一个缓冲区的概念

也就是,当我们使用了\n之后就会自动刷新缓冲区,但是\r不会

我们不想用\n是因为不想出现下面这样的情况:

所以我们只想回到第一行然后从头开始覆盖式地进行写入

但是如果是\r的话,就会出现一个情况就是,我们会等到程序结束之后才会把最后一次的结果打印出来,这时因为缓冲区不会因为\r刷新

所以我们这时候就需要fflush(stdout),这样就能在不回车的前提下达到提前刷新缓冲区的效果了

至于stdout,这就是系统默认打开的标准输出文件,其实我们这里可以粗浅的看作就是显示器,我们需要刷新缓冲区才能让显示器上显示结果

倒计时

至于倒计时,其实相当简单,我们只需要知道,这是在不停地打印数字,并且会在同一个位置打印,这就需要用到回车(\r)回到最前面,然后覆盖掉前面的结果以达到原地变化的效果

但是由于\r不会刷新缓冲区,所以我们就需要使用fflush刷新,这样,我们的倒计时就写好了

代码如下:

void time_count_down(int total)
{int cnt = total;while(cnt >= 0){printf("倒计时: %2d\r", cnt);fflush(stdout);cnt--;usleep(300000);}printf("\n");
}

进度条

首先,我们需要知道的是,进度条的本质和倒计时是一样的,就是\r移动光标,通过覆盖式写入达到变化的效果

我们先来看看成品的样子:

分析一下,首先我们需要预留出一百个空间,表现出递进的效果

这一步我们可以直接建一个数组,然后一个循环,每循环一次,就打印出当前数组里面的内容,并且在当前数组最后一个 “ = ” 后面再加一个等号,这样,我们就达到了循环递进的效果

但是,我们需要注意的是,这期间我们需要一直使用 \r 和 fflush,如下:

#define LENGTH 101
#define STYLE '='void ProcessBar()
{char bar[LENGTH];memset(bar, '\0', sizeof bar);int cnt = 0;while(cnt <= 100){printf("[%-100s]\r", bar);fflush(stdout);bar[cnt++] = STYLE;usleep(10000);}printf("\n");
}

注意,上面的 “%-100d” 中,100就代表默认留出100个位置,-100则代表左对齐

接着,我们可以看到,进度条后面还有两个东西:

这两个,一个是实时显示当前加载进度的数字显示,还有一个是想通过 |/-\ 这四个字符,达成一条线在不停旋转的动态效果,也就是在提醒用户,可能用户看到进度条不动了以为是网卡了,但其实还在下载,只是进度比较慢,暂时卡住了而已,动态的话就是为了避免这个问题

首先来解决第一个

这个其实我们只需要把数字填进去就可以了,只是后面的%需要写两个而已,写一个显示不出来

而最后一个就是,我们先写一个数组:

const char* label = "|/-\\";

我们只需要不停的从左往右选择即可,但是由于会越界,所以我们就需要%一个数组大小,这样才不会越界

而其中 \\ 有两个是因为只写一个不显示

比如,我现在数组大小是4,如果当前数字大小是4,4%4 = 0,那么就会直接回到第一个数组下标位置,5%4就是1,代表第二个位置,依此类推

总代码如下:

#define LENGTH 101
#define STYLE '='
const char* label = "|/-\\";void ProcessBar()
{char bar[LENGTH];memset(bar, '\0', sizeof bar);int len = strlen(label);int cnt = 0;while(cnt <= 100){printf("[%-100s][%3d%%][%c]\r", bar, cnt, label[cnt % len]);fflush(stdout);bar[cnt++] = STYLE;usleep(10000);}printf("\n");
}

进度条进阶版

现实中,我们的进度条都是搭配了任务一起的

比如我们可以写一个下载的任务,影响下载的因素这里假设只有带宽,他就相当于下载速度吧在这里

然后我们只需要提供一个文件总大小,模拟这个过程即可

代码如下(模拟下载任务的代码):

#define bandwidth 1024*1024*1.0;void download(double file_size)
{double current = 0.0;while(current <= file_size){//调用进度条ProcessBar(file_size, current);current += bandwidth;usleep(20000);}printf("\n");
}

这时候我们的进度条文件就需要更改一下了

由于会被频繁调用,所以我们的进度条在这里,每一次调用都代表那一瞬间的状态

所以我们在进度条那里的循环可以只是循环添加 =

接着,我们的进度这次就是按照百分比来算的了

所以进度条需要一个总的文件大小,以及现在文件加载到哪里了,这样我们将两个文件除出来之后再乘100,就是当前文件加载的百分比进度:

double rate = current*100.0/total;

接下来的都是小小修改一下而已,代码如下:

#define LENGTH 101
#define STYLE '='
const char* label = "|/-\\";void ProcessBar(double total, double current)
{char bar[LENGTH];memset(bar, '\0', sizeof bar);int len = strlen(label);double rate = current*100.0/total;int loop_count = (int)rate;int cnt = 0;while(cnt <= loop_count){bar[cnt++] = STYLE;}printf("[%-100s][%.1lf%%][%c]\r", bar, rate, label[cnt % len]);fflush(stdout);
}

最后,我们还可以再来一个小优化

试想一下,我们以后如果有了图形化界面,或者就是单纯更好的进度条,对于这个下载任务而言,如果我们只是用一个函数指针的话,到时候我们只需要修改指针即可,这样的话,修改起来就很方便,当我们有了更好的进度条的时候

如下,我们可以先在 .h 文件里面定义一个函数指针:

typedef void (*pb)(double, double);

接着,我们的下载任务里面,就可以直接加上这个参数了:

#define bandwidth 1024*1024*1.0;void download(double file_size, pb procbar)
{double current = 0.0;while(current <= file_size){procbar(file_size, current);current += bandwidth;usleep(20000);}printf("\n");
}int main()
{download(100.0*1024*1024, ProcessBar);return 0;
}

结语

这篇文章到这里就结束啦!!~( ̄▽ ̄)~*

如果觉得对你有帮助的,可以多多关注一下喔

相关文章:

  • MySQL迁移SSL报错
  • VideoMAE论文笔记
  • 【sylar-webserver】10 HTTP模块
  • SSL/TLS证书申请与管理技术指南
  • LLM推理加速技术如何迁移到传统 Transformer 模型(ASR)
  • Ubuntu nginx 配置 SSL 证书支持 https 请求
  • 【2025-05-22】centos 离线安装兼容node和npm版本的pm2 和 yarn
  • 《深度掌控Linux:openEuler、CentOS、Debian、Ubuntu的全方位运维指南》
  • 【2025-05-22】XXL-JOB 的 8810 端口添加到 CentOS 6.5 的防火墙白名单
  • Dify-4:API 后端架构
  • 开源无界 智联欧陆——仓颉计划携手OpenHarmony共绘万物互联新图景
  • 将 Docker 镜像推送到 GitLab Container Registry 的完整步骤
  • Java 调用 GitLab API
  • OpenHarmony外设驱动使用 (十二),User_auth
  • ubuntu20.04vscode使用C++20(调整gcc版本vscode设置)
  • day 33简单的神经网络
  • GitLab 备份所有仓库(自动克隆)
  • Spring Boot 内置工具类汇总与讲解
  • 人民日报社主管媒体深度聚焦珈和科技“遥感+AI”农险精准化突破:首创“四维数据贯通”模式 树行业转型新标杆
  • 塔能科技:工厂能耗精准节能全方位解决方案
  • 青海互动网站建设/百度用户服务中心
  • 国际业务网站有哪些/现在最好的营销方式
  • 免费手机端网站模板下载/百度指数名词解释
  • 企业做网站的/企业文化的重要性和意义
  • python语言好学吗/seo怎么优化效果更好
  • 搜索引擎推广特点/东营seo网站推广