Linux 编写一个 简单进度条

进度条

回车换行理解:

我们要理解,回车换行是两个概念:

  • 换行是把光标移到下一行,是竖直的往下平移;" \n "
  • 回车是把光标移到当前行的最开始;                  " \r " 

 就和一起打字机一样:

 在打字的时候,有一个 负责打印印刷在纸上的机器,是跟随者使用人打印文字,往有迭代走的,当这个机器走到 最右边的时候,或者使用人想要再次换行的时候,使用人机会把这个机器从最右边 手动 移动到 最左边,这个过程就和上述的 "r " 换行一样。

而且在换行的时候,纸还会往上走,这个过程就相当于是 回车了。

还有老式键盘的回车键,是 一个 从上往下,从左往右的造型:

 这也是模拟了 此处的回车键 是代表的是 回车换行的作用。

 缓冲区理解

 首先我们来看一个简单的代码:

 我们在 Linux 下运行这个代码的话,会先打印 hello C! 然后 程序休眠两秒 才会出来下一个 word:

 但是这是我们在printf 当中输出了 \n 的情况;如果不输出  \n 的话 又会是什么情况呢?

程序源码展示:

 输出:

 发现好像不对劲啊,C语言一定是从 上往下执行的,那么应该是 先输出 hello C! 然后在 休眠啊。

但是看上述的输出结果,好像是 休眠在输出啊?

所以,上述printf()已经打印完毕了,只不过还没有显示出来,那么在 sleep()的两秒内,这个 "hello C!" 字符串是在哪里存储的呢?

其实就是存储在 缓冲区当中的,因为 上述使用 C语言编写代码,所以此时,这个缓冲区是由 C语言管理的一块缓冲区。

当程序 sleep 结束了在缓冲区当中的数据才会被刷出来。

C程序默然会为我们打开三个 输入输出流:标准输入,标准输出(显示器,输出类型为 stdout),标准错误。

stdout 其实就是 FILE* 类型;

 我们可以使用 stdio.h 当中的 fflush(FILE* stream)函数,强制把 缓冲区当中的数据给刷出来。

 输出:

 至此,我们就可以简单的实现一个倒计时了:

 上述的 "-" 表示每一次都从 最左边开头输出;"2" 表示,不管当前输出什么,都按照两个字符输出;"\r" 表示每一次都当前行的最左边输出。

如果不加 "\r" 将会是 一秒输出一个数字 输出: 109876543210 。

进度条实现

那么在linux 当中,实现一个简单的进度条就和上述倒计时小程序是类似的,我们只需要把 每一次 光标移动到最前面的时候输出的字符,从 1 个,改为依次增加一个字符输出就行了。

利用就是 linux 当中不使用 "/n" 等等类似操作的话,就不会立即刷新缓冲区当中的内容,我们把这种刷新方式称之为 行刷新。比如:使用 "\r" 回车的话,就不会立即刷新 缓冲区当中的内容,也就不会立即打印出来。

我们可以使用 fflush(stdout)的方式来强制输出 缓冲区当中的内容。

我们先把 中间填充的部分完善,按照上述倒计时的方式修改。

 上述printf()函数当中的输出,“100” 是为了保证 在 “[]”当中一直有最大 100 个字符的 “\0” 填充,"-" 代表从当前行最左边开始输出(因为 当使用上述 的填充之后,C语言默认从最最右边开始输出), "%%" 是输出一个 "%",因为 "%" 这个字符在printf ()当中是格式化输出的字符,所以只能直接用,当然 可以 "/%" 使用转移字符。

上述输出:

 但是,上述的进度条有点太单一了,我们还可以加上一些旋转图标等等,我们就简单实现,覆盖式打印 "|"  "/"  "--" "\"  "|"  ,简单实现。

完整代码:

  1 #include<stdio.h>2 #include<unistd.h>3 #include<string.h>4 5 #define NUM 1006 #define STYLE '='7 #define RIGHT '>'8 #define TOP 1009 #define SPEED 1000010 11 const char* labar = "|/-\\";12 13 void processbar(int speed)14 {15   int cn = 0;16   char array[NUM];17 18   memset(array, '\0', sizeof(array));19   int len = strlen(labar);20 21   while(cn<TOP)22   {23     printf("[%-100s][%d%%][%c]\r",array, cn + 1 ,labar[cn%len]);24     fflush(stdout);25     array[cn++] = STYLE;26 27     if(cn < TOP) array[cn] = RIGHT;                                                                                 28     usleep(SPEED);29   }30   printf("\n");31 }32 33 int main()34 {35   processbar(10000);36   37   return 0;38 }

上述是进度条自己在运行,但是我们在使用进度条的时候,一般都是记录一下外部程序运行的进度的,那么进度条函数本身是不知道的,只有外部程序调用者才知道当前 程序的进度,所以我们还需要对上述进度条进行改进:

#include<stdio.h>
#include<unistd.h>
#include<string.h>#define NUM 100
#define STYLE '='
#define RIGHT '>'
#define TOP 100const char* labar = "|/-\\";
char array[NUM] = { 0 };void processbar(int rate)
{if (rate < 0 || rate > 100) return;17   int len = strlen(labar);printf("[%-100s][%d%%][%c]\r", array, rate, labar[rate % len]);fflush(stdout);array[rate++] = STYLE;if (rate < 100) array[rate] = RIGHT;
}int main()
{int total = 1000; // 比如现在要下载一个 1000MB的文件int curr = 0;//因为进度条是在外部使用进度条的人才知道当前程序的进度
//所以 循环不能写在 进度条函数当中
//应该写在外部while (curr <= total){//这里就模拟外部程序运行了processbar(curr * 100 / total);curr += 10;usleep(50000);}printf("\n");return 0;
}

此时,在进度条函数当中,就只有 100 打印当中的一次答打印,我们把 循环做到了外层 程序当中。

其实还可以更简化,可以使用 函数指针类型 来实现更简单的进度条调用

typedef void (*callback_t)(int); // 函数指针类型// 模拟一种下载
void download(callback_t cb)
{int total = 1000;int curr = 0;while (curr <= total){// 此时正在下载usleep(50000); // 模拟下载时间int rate = curr * 100 / total;cb(rate);// 通过函数指针的回调,调用 processbar函数curr += 10;}printf("\n");
}
void processbar(int rate)
{if (rate < 0 || rate > 100) return;int len = strlen(labar);printf("[%-100s][%d%%][%c]\r", array, rate, labar[rate % len]);fflush(stdout);array[rate++] = STYLE;if (rate < 100){array[rate] = RIGHT;}else{initarray();}
}

 

如上所示,我们模拟实现一个 下载软件的 过程,把 进度条函数通过函数指针的方式传入到 download当中,在 download()函数当中,通过函数指针调用到 进度条函数,就可以简便的调用进度条函数。

 所以,在主函数当中,我们只需要调用 download()函数,就行:

int main()
{download(processbar);return 0;
}

 上述就是 简单的进度条实现,当然,你还可以用 C当中一些颜色输出来美化 进度条:
c语言中如何更改输出字符的颜色 - CSDN文库

 

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

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

相关文章

【计网】傻瓜式安装cpolar内网穿透

目录 一、注册账户 二、下载安装包 三、安装 四、查看AuthToken 五、简单使用 如果在本机部署项目外网是访问不到的&#xff0c;通过内网穿透就可以使本机部署的项目可被外网访问 一、注册账户 cpolar - secure introspectable tunnels to localhostcpolar secure intro…

数字技术助力智慧公厕,让公厕变身为全新创新应用

在如今数字化的时代&#xff0c;数字技术的集成应用已经渗透到了生活的方方面面。其中一个令人瞩目的领域就是智慧公厕。以前只是简单的厕所&#xff0c;如今借助数字技术的力量&#xff0c;智慧公厕变得功能强大、智能高效。接下来&#xff0c;我们将以智慧公厕源头领航厂家广…

数据治理是一个怎样的体系化的过程?_光点科技

数据治理是一个复杂而系统化的过程&#xff0c;旨在确保企业能够有效地管理、维护和利用其日益增长的数据资产。这一过程涉及多个层面和步骤&#xff0c;需要有明确的框架和战略规划。 数据治理的体系化始于明确定义的目标和愿景。企业需要明确意识到数据对于业务成功的重要性&…

微信小程序开发--入门

目录 前言 一.准备阶段 1.申请账号 2.安装开发工具 二.开发第一个小程序 1.创建项目 2.基础操作及语法 2.1目录结构 2.2 常见语法及文件类型 ​编辑 3.案例演示开发 1.新建页面 2.新建标题 3.后端传值 前言 简介&#xff1a; 微信小程序&#xff08;WeChat …

蓝桥杯(七段码,C++)

思路&#xff1a; 1、把灯管的连接转为图结构&#xff0c;相邻的灯管即认为有边。 2、用深度搜索&#xff0c;去计算有多少种不同字符。 3、因为有每种字符都会重复算两遍&#xff0c;最后的结果需要数以2。 #include <iostream> using namespace std;int graph[7][7…

腾讯云国际站-阿里云OSS如何迁移到腾讯云COS?腾讯云cos迁移教程

下面小编将介绍当源对象存储部署在阿里云国际版OSS 时&#xff0c;如何配置全托管迁移任务和半托管迁移任务&#xff0c;实现顺利迁移数据至腾讯云国际版COS。 准备工作 阿里云对象存储 OSS 创建 RAM 子账号并授予相关权限&#xff1a; 登录 RAM 控制台。选择人员管理 > …

发货100虚拟商品自动发货系统存在SQL注入

漏洞描述 该系统存在SQL注入漏洞&#xff0c;可获取敏感信息及账号密码。 漏洞复现 构造SQL注入延时payload&#xff1a; M_id11%20AND%20(SELECT%208965%20FROM%20(SELECT(SLEEP(5)))sdhh)&typeproduct漏洞证明&#xff1a; 文笔生疏&#xff0c;措辞浅薄&#xff0c;…

ElasticSearch-Head 数据浏览406问题解决

解决方法&#xff1a; 1、打开Docker DeskTop的Containers&#xff0c;找到es-head容器 2、选择Exec Tab选项 3、编辑vendor.js文件 vim _site/vendor.js 4、显示行号 :set nu 5、修改配置 # 修改文件第6886、7574行 将"application/x-www-from-urlencodes"修改…

centos6/7 SOCKS5 堆溢出漏洞修复(RPM方式)curl 8.4 CVE-2023-38545 CVE-2023-38546

引用 https://darkdark.top/update-curl.html centos6 rpm 升级包下载&#xff1a;https://download.csdn.net/download/sinat_24092079/88425840 yum update libcurl-8.4.0-1.el6.1.x86_64.rpm curl-8.4.0-1.el6.1.x86_64.rpmcentos7 rpm 升级包下载&#xff1a;https://down…

BuyVM 挂载存储块

发布于 2023-07-13 on https://chenhaotian.top/linux/buyvm-mount-block-storage/ BuyVM 挂载存储块 参考&#xff1a; https://zhujitips.com/2653https://www.pigji.com/898.html 1 控制台操作 存储块购买完毕后&#xff0c;进入后台管理界面&#xff0c;进入对应 VPS …

多测师肖sir_高级金牌讲师_python之模块008

python之模块 一、模块的介绍 &#xff08;1&#xff09;python模块&#xff0c;是一个python文件&#xff0c;以一个.py文件&#xff0c;包含了python对象定义和pyhton语句 &#xff08;2&#xff09;python对象定义和python语句 &#xff08;3&#xff09;模块让你能够有逻辑…

【Tomcat】Apache发布两个新版本Tomcat修复多个Bug

Apache 官网发布了两个最新的 Tomcat 版本包&#xff0c;分别是&#xff1a;8.5.94、9.0.81 这两个最新版本修复了多个漏洞&#xff0c;统计信息如下表所示。有关漏洞的详细信息&#xff0c;请查阅官方相关文档&#xff08;见&#xff1a;参考&#xff09;。 严重等级漏洞说明…

卷积神经网络CNN基础知识

目录 1 前言2 卷积神经网络CNN2.1 LeNet-5相关介绍2.2 CNN基本结构2.2.1 卷积层2.2.2 池化层&#xff08;下采样层&#xff09;2.2.3 全连接层2.2.3.1激励层&#xff08;非线性激活&#xff09;2.2.3.2 线性层2.2.3.3 Dropout层2.2.3.4 总结 2.3 图像的上采样和下采样2.3.1 上采…

联盟链学习笔记-网络的创建

联盟链学习笔记 初始网络 下图是初始网络网络N的参考图 排序服务 在定义 网络 N 的时候&#xff0c;第一件事情就是定义一个 排序服务O4。O4 最初被配置并且由组织 R4 的一个管理员来启动&#xff0c;并且由 R4 管理。配置 NC4 包含了描述网络管理能力初始集合的规则。最初…

微软开源 windows-drivers-rs,用 Rust 开发 Windows 驱动程序

导读Microsoft Azure 首席技术官兼著名 Windows 软件开发人员 Mark Russinovich 在社交平台上宣布&#xff0c;启动了一个名为 windows-drivers-rs 的新开源项目。 该项目可帮助开发人员使用 Rust 开发 Windows 驱动程序&#xff0c;旨在支持 WDM (Windows Driver Model) 和 W…

【C语言】程序环境和预处理

程序环境&#xff1a; 1、C语言的任何一种实现&#xff0c;存在两个不同的环境&#xff1b; 2、翻译环境&#xff1a;将源代码转换成可执行的二进制指令&#xff08;机器指令&#xff09;&#xff1b;.c文件&#xff08;源文件——文本信息的代码&#xff09;->&#xff0…

微服务12-分布式服务理论基础+Seata的认识

文章目录 分布式服务理论基础前言微服务和分布式的区别CAP定理BASE理论 Seata流程&#xff1a;seata部署微服务集成seata 分布式服务理论基础 前言 单体架构&#xff1a; 1.项目过于臃肿&#xff0c;所有服务在一起&#xff0c;一个业务挂了&#xff0c;整个项目就不能用了&…

腾讯云我的世界mc服务器多少钱一年?

腾讯云我的世界mc服务器多少钱&#xff1f;95元一年2核2G3M轻量应用服务器、2核4G5M带宽优惠价218元一年、4核8G12M带宽轻量服务器446元一年&#xff0c;云服务器CVM标准型S5实例2核2G优惠价280元一年、2核4G配置服务器748元一年&#xff0c;腾讯云百科txybk.com分享腾讯云我的…

人事管理系统springboot42

大家好✌&#xff01;我是CZ淡陌。一名专注以理论为基础实战为主的技术博主&#xff0c;将再这里为大家分享优质的实战项目&#xff0c;本人在Java毕业设计领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目&#xff0c;希望你能有所收获&#xff0c;少走一些弯路…

HNU-计算机网络-讨论课1

题目&#xff1a; 有关网络系统结构的讨论 一、必选问题&#xff08;每组平均每人1个&#xff09; 1、分层结构其实是世界演进形成的普遍系统结构&#xff0c;不管是自然领域还是社会领域&#xff0c;请举例说说你的理解。 2、有人说通信网络的核心技术在物理层&#xff0c…