【Linux】简易进度条的实现

图片名称
🎉博主首页: 有趣的中国人

🎉专栏首页: Linux

🎉其它专栏: C++初阶 | C++进阶 | 初阶数据结构

在这里插入图片描述

小伙伴们大家好,本片文章将会讲解Linux进度条的实现的相关内容。


如果看到最后您觉得这篇文章写得不错,有所收获,麻烦点赞👍、收藏🌟、留下评论📝。您的支持是我最大的动力,让我们一起努力,共同成长!

文章目录

  • `1. 关于回车 & 换行`
  • `2. 简述缓冲区`
  • `3. 倒计时程序的编写`
  • `4. 简易进度条的实现`



1. 关于回车 & 换行



回车和换行是文本显示和处理的相关术语,我们常常认为这两个是同一概念,实则不然。


👨‍💻回车换行的概念


回车(Carriage Return)在打字机时代,回车指的是将打字机的打印头(称为"carrier")移回到行首的操作在计算机时代,回车通常表示将光标移动到当前行的开头而不会换到下一行。在ASCII字符集中,回车通常用"\r"表示。

换行(Line Feed):换行是指将光标移动到下一行的操作使得文本在纵向上向下移动一个行高。在ASCII字符集中,换行通常用"\n"表示。


在Unix和类Unix系统(如LinuxmacOS)中通常使用换行字符(“\n”)来表示换行。

在Windows系统中:通常使用回车和换行的组合来表示换行,即"\r\n"。



2. 简述缓冲区


缓冲区(Buffer)是计算机内存中的一块特定区域,用于临时存储数据。它在许多计算机系统和应用程序中发挥着重要作用,通常用于临时存储输入数据、输出数据或在内存和其他设备之间进行数据传输。

输入缓冲区:用于暂时存储从输入设备(如键盘、鼠标、网络接口等)接收到的数据,直到程序能够处理它们。输入缓冲区使得程序可以按需处理输入,而不必担心输入数据的速度与程序处理速度不匹配的问题

输出缓冲区:用于暂时存储将要发送到输出设备(如显示器、打印机、网络接口等)的数据,直到设备准备好接收它们。输出缓冲区可以提高数据传输的效率,因为程序不必等待设备就绪就可以继续执行。


👨‍💻缓冲区何时被清理

拿C语言举个例子:

在C语言中,标准库函数printf()用于将格式化的数据打印到标准输出流(通常是终端)。但是,printf()函数并不会立即将数据显示到终端上。相反,它会将数据写入到输出缓冲区中。输出缓冲区是一个临时存储区域,用于存放printf()函数打印的数据,直到满足一定条件时才将其刷新(即将数据发送到终端并显示出来)。

这些条件包括:

1. 遇到换行符 \nprintf()函数遇到换行符时,输出缓冲区会被自动刷新,将缓冲区中的数据输出到终端并显示出来。

2. 缓冲区满:当输出缓冲区满了,它也会被自动刷新。

3.调用fflush()函数:显式调用fflush(stdout)函数可以强制刷新输出缓冲区,将其中的数据输出到终端。

4. 程序结束:当程序正常终止时,所有的缓冲区都会被刷新。



3. 倒计时程序的编写


有了以上的知识储备,咱们就可以尝试编写一下简单的倒计时程序了,思路如下:

  • 首先新建一个time.c文件,然后再用我们之前讲的makefile工具来实现time.c文件的自动构建:

在这里插入图片描述

  • 编写time.c这个文件,实现思路:
  1. 假设我们倒数10s,到0s时结束,因此需要一个循环;
  2. 循环中,我们要实现每次出来一个数,都要对之前的数进行覆盖,所以要用到回车"\r";
  3. 由于printf()函数会会将输出的结果先输出到缓冲区,回车不会冲刷缓冲区,因此每次要用fflush(stdout)强制冲刷缓冲区;
  4. 每次循环秒数减1,并让程序休眠1s

🌝详细代码如下:

#include <stdio.h>
#include <unistd.h>
int main()
{int cnt = 10;while(cnt >= 0){// 打印的时候每次覆盖上一次出现的数字printf("倒计时:%2d\r",cnt);// 强制冲刷缓冲区fflush(stdout);--cnt;sleep(1);}printf("\n");return 0;
}
  • make命令进行编译:(⏳这边就可以动态运行了哈,感兴趣的可以自己试一下⌛)

在这里插入图片描述

  • 这里有个小拓展,如果我们要覆盖上次的数字是4位,这次是三次(比如1000到999),可以用%4d这个输出形式来解决,也可以用下面这种方法:
#include <stdio.h>
#include <unistd.h>
int main()
{int cnt = 1000;int tmp = cnt;int num = 0;while (tmp){++num;tmp /= 10;}while(cnt >= 0){// 主要就是这里的变化,用最大数字的位数来做占位符printf("倒计时:%*d\r",num, cnt);fflush(stdout);--cnt;sleep(1);}printf("\n");return 0;
}


4. 简易进度条的实现



好啦,有了以上的知识作为基础,咱们就可以进入正题啦!😎编写简易的进度条。😎


👨‍💻效果图展示

总共有三个部分:

1. 我们要实现的进度条用#来进行加载;

2. 后面要有数据来表示现在加载的进度是多少(百分数);

3. 最后用一个动态旋转的类来表示程序还在继续加载


在这里插入图片描述

👨‍💻实现思路


1. 动态加载的过程

动态加和之前的倒计时差不多,每次都要覆盖上次出现的#,具体思路如下:


1. 定义一个字符类型数组char *str,用memset()函数进行初始化(‘\0’);

2. 循环100次,每次循环都在数组中加一个#,并打印str('\r’进行覆盖);

3. 强制冲刷缓冲区;


2. 进度加载

我们可以用每次循环的次数来当作是当前加载的进度,当然还要进行覆盖,具体思路如下:


1. 每次循环都以当前的循环次数作为加载进度;

2. 每次覆盖上一次的进度;

3. 强制冲刷缓冲区。

4. 程序休眠(可以用usleep()函数,单位是微秒)


3. 动态旋转

定义一个数组,并初始化为-\\/-,覆盖的方法和之前类似,就不详细说了。


👨‍💻具体代码实现

#include "process_bar.h"
#include <memory.h>
#include <unistd.h>
#define style '#'
#define round "-\\/-"
void test()
{int i = 0;char str[100];memset(str,'\0',sizeof(str));while (i <= 100){str[i] = style;printf("[%-100s][%d%%][%c]\r",str,i,round[i % 4]);fflush(stdout);++i;usleep(10000);}printf("\n");
}

在这里插入图片描述



👨‍💻第二版本

我们正常用进度条肯定不是单独使用的,会结合其他的场景,例如下载界面,登陆界面


对于要下载的文件,肯定有文件大小,下载的时候网络也有它的带宽,所以在下载的时候,每次下载的大小都是一个带宽,我们可以先写一个下载的函数:

download函数:

void download()
{double bandwidth = 1024 * 1024 * 1.0;double filesize = 1024 * 1024 * 10.0;double cur = 0.0;while (cur <= filesize){// 调用进度条函数test(filesize, cur);// 每次增加带宽cur += bandwidth;usleep(20000);}printf("\n");printf("this file has been downloaded\n");
}

进度条函数:

void test(double total, double current)
{char str[101];memset(str,'\0',sizeof(str));int i = 0;// 这次的比率double rate = (current * 100) / total;// 循环次数int loop_count = (int)rate;while (i <= loop_count){str[i++] = style; }printf("[%-100s][%.1lf%%][%c]\r",str,rate,round[loop_count % 4]);fflush(stdout);
}

回调函数版本(完整):

// 头文件 process_bar.h
#include <stdio.h>typedef void(*callback_t)(double, double);// 函数指针(回调函数)void test(double total, double current);// 函数实现文件 process_bar.c
#include "process_bar.h"
#include <memory.h>
#include <unistd.h>
#define style '#'
#define round "-\\/-"void test(double total, double current)
{char str[101];memset(str,'\0',sizeof(str));int i = 0;double rate = (current * 100) / total;int loop_count = (int)rate;while (i <= loop_count){str[i++] = style; }printf("[%-100s][%.1lf%%][%c]\r",str,rate,round[loop_count % 4]);fflush(stdout);
}// main.c 主函数和 download 函数
#include "process_bar.h"
#include <unistd.h>double bandwidth = 1024 * 1024 * 1.0;
void download(double filesize, callback_t cb)
{double cur = 0.0;while (cur <= filesize){cb(filesize, cur);cur += bandwidth;usleep(20000);}printf("\n");printf("this file has been downloaded\n");
}int main()
{download(1024*1024*100.0,test);download(1024*1024*20.0,test);return 0;
}

在这里插入图片描述

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

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

相关文章

深度学习论文: LightGlue: Local Feature Matching at Light Speed

深度学习论文: LightGlue: Local Feature Matching at Light Speed LightGlue: Local Feature Matching at Light Speed PDF: https://arxiv.org/pdf/2306.13643 PyTorch代码: https://github.com/shanglianlm0525/CvPytorch PyTorch代码: https://github.com/shanglianlm0525/…

AI算法-高数2-导数定义和公式

P14 2.1 导数的定义(一):2.1 导数的定义_哔哩哔哩_bilibili 导数定义&#xff1a; 导数公式&#xff1a; P15 2.1 导数的定义(二)&#xff1a;2.1 导数的定义&#xff08;二&#xff09;_哔哩哔哩_bilibili [a,b]可导&#xff0c;a的端点&#xff1a;右可导&#xff0c;b端点&…

Leetcode—138. 随机链表的复制【中等】(cend函数)

2024每日刷题&#xff08;129&#xff09; Leetcode—138. 随机链表的复制 实现代码 /* // Definition for a Node. class Node { public:int val;Node* next;Node* random;Node(int _val) {val _val;next NULL;random NULL;} }; */class Solution { public:Node* copyRan…

Spring JdbcTemplate使用临时表+事务会话管理实现数据新增、查询及自动清除功能

需求描述&#xff1a; 由于某些情况下当查询过滤参数过大时&#xff0c;执行sql由于参数过大而报错&#xff0c;此时 需要使用临时表的方式&#xff0c;即 当参数超过某个阀值&#xff08;如 1000&#xff0c;可调整&#xff09;新增一张临时表&#xff0c;将原表 与 该临时表进…

代码随想录算法训练营第六十二天|503.下一个更大元素II、42.接雨水

代码随想录算法训练营第六十二天|503.下一个更大元素II、42.接雨水 503.下一个更大元素II 给定一个循环数组 nums &#xff08; nums[nums.length - 1] 的下一个元素是 nums[0] &#xff09;&#xff0c;返回 nums 中每个元素的 下一个更大元素 。 数字 x 的 下一个更大的元…

第十一篇:操作系统新纪元:智能融合、量子跃迁与虚拟现实的交响曲

操作系统新纪元&#xff1a;智能融合、量子跃迁与虚拟现实的交响曲 1 引言 在数字化的浪潮中&#xff0c;操作系统如同一位智慧的舵手&#xff0c;引领着信息技术的航船穿越波涛汹涌的海洋。随着人工智能、物联网、量子计算等前沿技术的蓬勃发展&#xff0c;操作系统正站在一个…

富士Apeos 2350 NDA复印机报062 360代码故障

故障描述&#xff1a; 富士Apeos 2350 NDA复印机新机器刚拆箱安装&#xff0c;开机正常&#xff0c;自检扫描头一卡一卡的往前动几下就不动了、扫描灯也不亮扫描头也不能正常复位&#xff1b;按机器的复印键直接报062 360代码&#xff1b; 解答&#xff1a; 此代码为扫描故障&a…

PDF高效编辑:一键批量,PDF转图片的快速解决方案

在数字化时代&#xff0c;PDF文件已成为工作和学习中不可或缺的一部分。然而&#xff0c;有时我们可能需要将PDF转换为图片&#xff0c;以便更轻松地编辑、共享或处理。为了满足这一需求&#xff0c;许多高效的PDF编辑工具应运而生&#xff0c;其中“办公提效工具”一键批量PDF…

【每日八股】淘天一面

&#x1f525; 个人主页: 黑洞晓威 &#x1f600;你不必等到非常厉害&#xff0c;才敢开始&#xff0c;你需要开始&#xff0c;才会变的非常厉害 rocketmq的消息重复发送问题&#xff1f;如何保证幂等&#xff1f; 如何保证幂等性&#xff1a; 消息 Key 设置&#xff1a;不建议…

如何自定义Markdown中插入图片的位置

工作中常常需要在VsCode下写Markdown笔记&#xff0c;在写笔记的过程中不免需要插入图片。  Markdown中插入笔记的操作往往是比较繁琐的&#xff0c;比如&#xff1a;在文档中引用本地某个文件夹下的图片&#xff0c;首先需要你先保存图片到本地路径&#xff0c;然后需要你在文…

Vue-Cli脚手架项目的搭建【新手快速入手】

目录 一、Vue CLI脚手架简介☺ 1.Node.js前置环境的安装 2.安装npm管理器 3.安装淘宝镜像(cnpm) 二、安装vue-cli 1. 版本号查看 2.旧版本卸载 3.新版本安装 4.检查 三、Vue项目的搭建 &#x1f4cc;进入Vue项目管理器 ★命令方式创建 若localhost拒绝访问怎么办&…

技术速递|Python in Visual Studio Code 2024年5月发布

排版&#xff1a;Alan Wang 我们很高兴地宣布 Visual Studio Code 的 Python 和 Jupyter 扩展将于 2024 年 5 月发布&#xff01; 此版本包括以下公告&#xff1a; “Implement all inherited abstract classes”代码操作新的自动缩进设置Debugpy 从 Python 扩展中删除&#…

Unity TileMap入门

概述 相信很多同学学习制作游戏都是从2D游戏开始制作的吧&#xff0c;瓦片地图相信大家都有接触&#xff0c;那接下来让我们学习一下这部分的内容吧&#xff01; Tilemap AnimationFrameRate:设置每帧动画的播放速率。Color:瓦片地图的颜色TileAnchor:锚点&#xff0c;&#x…

Docker容器创建各种镜像

目录 1.Docker创建Mysql容器 2.Docker创建Redis容器 3.Docker 创建minio容器 1.Docker创建Mysql容器 拉取镜像 docker pull mysql:8.0.20 宿主机创建挂载目录 /opt/mysql/conf /opt/mysql/data /opt/mysql/log 启动命令 docker run --name mysql -p 3306:3306 -v /opt/…

Set接口

Set接口的介绍 Set接口基本介绍 无序&#xff08;添加和取出的顺序不一致&#xff09;&#xff0c;没有索引不允许重复元素&#xff0c;所以最多包含一个nullJDK API中Set接口的实现类&#xff1a;主要有HashSet&#xff1b;TreeSet Set接口的常用方法 和List 接口一样&am…

Windows11提示升级,我要点确定吗?

Windows 11自2021年10月推出以来&#xff0c;一直保持着缓慢而稳定的增长&#xff0c;相对来说在游戏PC上的影响力较大&#xff0c; 而Windows 10也即将于2025年10月结束支持。 截至2024年&#xff0c;Windows 11的主要版本包括24H2、 23H2、22H2和21H2。 24H2&#xff1a;20…

k8s遇到的常见问题及解决

1. error: open /var/lib/kubelet/config.yaml: no such file or directory 解决&#xff1a;关键文件缺失&#xff0c;多发生于没有做 kubeadm init就运行了systemctl start kubelet。 要先成功运行kubeadm init 2. 执行初始化kubeadm init ------的时候报错 The HTTP call…

五一超级课堂---Llama3-Tutorial(Llama 3 超级课堂)---第四节Llama 3 高效部署实践(LMDeploy 版)

课程文档&#xff1a; https://github.com/SmartFlowAI/Llama3-Tutorial 课程视频&#xff1a; https://space.bilibili.com/3546636263360696/channel/collectiondetail?sid2892740&spm_id_from333.788.0.0 操作平台&#xff1a; https://studio.intern-ai.org.cn/consol…

GAMMA Lab——知识图谱和LLM大模型

图机器学习的发展与分类 图基础模型 LLM基础模型 GNN LLM 前沿工作

JUC下的CompletableFuture详解

详细介绍 CompletableFuture是Java 8引入的一个实现Future接口的类&#xff0c;它代表一个异步计算的结果。与传统的Future相比&#xff0c;CompletableFuture提供了更丰富的功能&#xff0c;比如链式调用、组合异步操作、转换结果、异常处理等&#xff0c;极大地增强了Java在…