【Linux】-----进度条小程序

目录

前言

基本知识

Ⅰ、回车和换行

Ⅱ、缓冲区

 两个有意思的现象

简单定义

刷新缓冲区

简易倒计时程序

进度条代码

多文件下makefile写法

一代(无任何场景)

procs1.h代码

procs1.c代码

主函数main1.c

一代运行结果:

二代 (搭配下载场景)

procs2.c代码

procs2.h代码

主函数main2.c 代码

二代结果显示:


前言

前面我们已经学会基本的Linux指令和工具,那么现在来搞个好玩的东西-进度条(简单版本)!!!

基本知识

Ⅰ、回车和换行

首先得明确,回车和换行对于我们而言就是一个简单的动作,可是对于机器来说这是两个独立的动作。

  • 换行

 换行是从末尾位置竖直向下移动一行,此时光标的位置是在下一行的末尾。

  • 回车

 回车是将光标移动到最左侧,也就是文段最开头的位置!

键盘上的回车键是先向下再向左的,对应的就是先换行再回车的两个动作!!

在C语言中,\n是表示回车换行同时,\r仅仅是回车。

Ⅱ、缓冲区

 两个有意思的现象

 ①有‘\n’

代码:

现象:

可以看到,执行这个程序时,先在屏幕上打印对应字符串,休眠3秒后结束程序!

②无‘\n’

代码:

现象:

可以看到这个现象和有‘\n’的不一样,没有'\n'开始运行时并没有打印字符串,而是休眠了3秒,退出程序的同时字符串一起显示出来。。

 对于无‘\n’的现象,我们需要明确一点,程序并不是先休眠了3秒才显示字符串,通俗点来说就是不是先执行sleep函数才去执行printf函数,同样也是先执行printf函数才去执行的sleep函数,因为程序是从上往下依次执行的。那么在这段休眠时间里字符串在哪?被放在了缓冲区里

简单定义

目前我们仅需知道缓冲区实际上就是一块内存空间,对于上面的字符串,就是被保存在这样的一块内存空间里,当程序运行结束时,会自动的刷新缓冲区里的内容到显示器上,所以无‘\n’才能看到上述的现象。

刷新缓冲区

①加上‘\n’,立即刷新

②等待缓冲区满或者程序结束,自动刷新

③强制刷新

怎么强制?

实际上C语言提供了一个的函数--fflush,这个函数就是用于强制刷新缓冲区的。。

这里的文件流后面的文章有详细讲解,现在我们只需要知道程序在运行时默认会打开三种流

  • 标准输入,stdin
  • 标准输出,stdout
  • 标准错误,stderr

我们的显示器就是标准输出文件,Linux下一切皆文件!所以可以采用该函数强制刷新到对应的文件流上。

演示:

 代码:

现象:

可以看到,即使程序没有‘\n’,也能直接显示字符串内容!!

有了上面的知识可以先来实现一个简单的倒计时程序

简易倒计时程序

 原理:实际就是对同一个位置进行覆盖进而实现一个动态的效果。

每当显示一个数字之后就将光标挪动至最前面(回车),休眠,然后再显示下一个数字。回车配休眠需要强制刷新缓冲区。

代码:

1 #include <stdio.h>2 #include <unistd.h>3 4 int main()5 {6   int cnt=10;7 8   while(cnt>=0)9   {10     printf("倒计时:%2d\r",cnt);11 12     fflush(stdout);//强制刷新到屏幕13     sleep(1);                                                                                                                                                           14     cnt--;15   }16   return 0;17 }

注意:为什么用%2d,是因为数字显示在屏幕上时,实际上是字符串的形式,相当于10是两个字符的字符串,需要覆盖两个字符。当然,大家感兴趣把2去掉看看! 

结果如下:

进度条代码

这里采用多文件的形式去实现的,为了更加方便的去管理代码。

多文件下makefile写法

一代(无任何场景)

procs1.h代码

主要是头文件的包含以及函数的声明!

#pragma once                                                                                                
#include <stdio.h>                                                                
#include <string.h>                                                                    
#include <unistd.h>                                                                                      void processbar1();     

procs1.c代码

主功能实现

代码如下:

#include "procs.h"#define Length 101 //进度条长度
#define Style '|' //进度条样式
const char* lab="|/-\\";//加载旋转光标
void processbar1()
{char bar[Length];//字符数组memset(bar,'\0',sizeof(bar));//初始化为\0int cnt=0;while(cnt<=100){printf("[%-100s][%3d%%][%c]\r",bar,cnt,lab[cnt%strlen(lab)]);//\r为了完成覆盖                                                                                       fflush(stdout); //强制刷新bar[cnt++]=Style;//字符追加至数组中usleep(100000);}printf("\n");}

代码解释:

①根据上述的效果图,进度条实际上是放在一个数组的中,所以定义一个长度为101的字符数组。数组按字节全部初始化为'\0'!

②因为要带来动态的效果所以运用上面提到的倒计时程序类似。回车('\r')配延时,强制刷新缓冲区

③%-100s:表示左对齐

④%3d%%:最后的双百分号,是为了取字面值%,以实现100%的效果。因为单独一个%在C语言中有着特殊含义。

const char* lab:字符串,同样最后的”\\“,也是为了取字面值\,防止转义,单独的\在C语言有着特殊含义。

⑥lab[cnt%strlen(lab)]:取模操作是为了防止数组越界!

主函数main1.c

调用函数即可。

 

一代运行结果:

二代 (搭配下载场景)

进度条不可能单独存在,一般常见的场景就是下载这一场景,会根据网络带宽,文件大小等其他的要素来决定下载进度,当然哦这里只是简单的模拟一下,没有涉及从网络获取数据等其他相关知识。

procs2.c代码

这里的改进主要是函数头包含了文件的总大小以及当前的下载进度。根据进度打印进度条!

#include "procs.h"#define Length 101 //进度条长度
#define Style '|' //进度条样式
const char* lab="|/-\\";//加载旋转标志
void processbar2(double total,double current)
{                                                                                                                                                                       char bar[Length];memset(bar,'\0',sizeof(bar));//初始化为\0int len=strlen(lab);int cnt=0;double rate=(current*100.0)/total;//计算比率int load_top=(int)rate;while(cnt<=load_top){bar[cnt++]=Style;//字符追加至数组中}printf("[%-100s][%.1lf%%][%c]\r",bar,rate,lab[cnt%len]);//\r为了完成覆盖fflush(stdout); //强制刷新
}

解释一下:

①因为主函数的下载功能是一个循环,会不断的调用该功能函数,每次的下载进度都不一样,因此需要计算每次的比率,再根据比率去打印进度条。。

②这里和一代的不同就是循环体,这里是先将字符一次性放进数组中,最后在一起刷新出来。如果不这样的话每次都会显示从0开始打印,并不是我们想看到的结果。。不信,你可以试试按照一代的写法。。

procs2.h代码

#pragma once #include <stdio.h>
#include <string.h>
#include <unistd.h>
typedef void(*Call_back)(double,double);//定义函数指针类型,为了方便回调                                                                                                    
void processbar2(double total,double current);

注意:这里声明了一个Call_back函数指针类型目的就是实现函数回调。因为未来可能还有更多版本的进度条功能代码, 采用函数指针的方式,只需要传入对应的函数名,就会去调用对应的功能代码。

主函数main2.c 代码

#include "procs.h"                                                    double bandwith=1024*1024*1.0;//下载速度1MB/s                         void download(double filesize,Call_back cb)//函数指针做参数                         
{                                                                     double cnt=0.0;                                                     printf("download begin....,bandwith is:%.1lf\n",bandwith);          while(cnt<=filesize)                                                {                                                                   cb(filesize,cnt);                                                 usleep(100000);                                                   cnt+=bandwith;                                                    }                                                                   printf("\ndownload finishi......,filesize is:%.1lf\n",filesize);    printf("\n");                                                       
}                                                                     
int main()                                                            
{                                                                     download(50.0*1024*1024,processbar2);//50MB                         download(10.0*1024*1024,processbar2);//10MB                        download(100.0*1024*1024,processbar2);//100MB                                                                                                                         return 0;
}

如代码,下载功能存在一个函数指针类型的参数,只需传入函数名(函数地址),就能找到对应函数的功能实现,效率极高也十分的巧妙。

二代结果显示:

可以看到,进度条会根据文件大小的不同,下载的速度也不一样,同一带宽情况下,文件越大,那必然越慢,如上图的10MB比100MB快多了。。

二代的场景更加贴近实际哦!!


 好了,今天的分享就到这里,如果对你有帮助,欢迎三连!!!

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

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

相关文章

在jmeter中使用javascript脚本

工作上遇到一个压力测试的需求&#xff0c;需要测试几个考试相关的接口。其中有一个获取试题详情的接口&#xff0c;和一个提交答题信息的接口。后一个接口以上一接口的返回内容为参数&#xff0c;添加上用户的答案即可。jmeter提供了非常多的方式可以实现该需求&#xff0c;这…

MySQL分组查询有关知识总结

目录 4. 分组查询&#xff08;group by&#xff09; 4.1 概述 4.2 分组函数 4.2.1 单个使用 4.2.2 组合使用 4.2.3 注意&#xff01; 4.3 group by 4.3.1 单个字段 4.3.2 多个字段 4.3.3 提醒&#xff01; 4.4 having 4.5 分组查询演示 4. 分组查询&#xff08;…

稀疏矩阵和稠密矩阵

1.csr_matrix compress sparse row&#xff0c;因此csr是按行压缩的稀疏矩阵。 稀疏矩阵由于0值过多&#xff0c;仅记有值的矩阵位置索引&#xff0c;如下图打印所示。 更多矩阵介绍参考这篇博文【Scipy学习】Scipy中稀疏矩阵用法解析&#xff08;sp.csr_matrix&#xff1b;s…

国家网络身份个人认证方法

申领网络身份认证后&#xff0c;用户会得到一张虚拟的“网络身份证”&#xff0c;它可以向需要实名认证的互联网平台进行认证&#xff0c;不再需要输入姓名和身份证号等信息。 申请方式&#xff1a;各手机应用平台搜索国家网络身份认证即可&#xff08;必须支持NFC才能申请&am…

大模型三种模式Embedding、copilot、Agent

大模型的三种应用模式——Embedding、Copilot、Agent——代表了不同级别的智能化和自动化程度&#xff0c;以及与人类用户的交互方式。下面是每种模式的具体解释&#xff1a; 嵌入模式&#xff08;Embedding Mode&#xff09; 定义&#xff1a;在嵌入模式中&#xff0c;大模型…

每日一题——贪心算法

1005. K 次取反后最大化的数组和 - 力扣&#xff08;LeetCode&#xff09; 题解&#xff1a; 一开始有点理解错他的意思&#xff0c;以为是i是题目中会给出&#xff0c;所以一开始没有什么思路&#xff0c;然后当看了题解之后&#xff0c;就知道了原来i是自己订的&#xff0c…

认识经典蓝牙

现在BLE很流行&#xff0c;本人接触BLE也更多&#xff0c;而对经典蓝牙BR/EDR的开发知之甚少&#xff0c;而且网上关于经典蓝牙的资料也很少&#xff0c;所以&#xff0c;想要有更多了解。 参考&#xff1a; https://www.nordicsemi.cn/news/bluetoothle-and-bluetoothclassic/…

网页设计师必备!10个免费的设计素材网站推荐

当网页设计师使用网页设计材料时&#xff0c;他们会优先考虑那些免费和高质量的网页设计材料网站。找到一个免费和高质量的网页设计材料网站并不容易&#xff0c;有些网站要么需要打开材料网站成员&#xff0c;要么设计材料质量很差。即时设计总结了10个免费的网页设计材料网站…

WEB服务器的详解与部署

WEB服务器也称为网页服务器或HTTP服务器 WEB服务器使用的协议是HTTP或HTTPS HTTP协议默认端口号&#xff1a;TCP 80 HTTPS协议默认端口号&#xff1a;TCP 443 浏览器其实就是 HTTP 客户端 WEB服务器发布软件 微软&#xff1a;IIS(可以发布web网站和FTP站点)linux&#x…

本科阶段最后一次竞赛Vlog——2024年智能车大赛智慧医疗组准备全过程——2Yolo使用之ONNX模型准备

本科阶段最后一次竞赛Vlog——2024年智能车大赛智慧医疗组准备全过程——2Yolo使用之ONNX模型准备 ​ 大家好&#xff0c;因为板端BPU环境&#xff0c;可以加速目标检测的速度&#xff0c;所以今天在此先给大家带来如何准备一个模型&#xff0c;下一期会给大家带来如何在板端部…

PromQL全方位解读:监控与性能分析的关键技术

一、PromQL简介 Prometheus Query Language (PromQL) 是一个专为Prometheus监控系统设计的强大查询语言&#xff0c;它允许用户对收集的时间序列数据进行高效、灵活的查询和分析。PromQL的设计哲学在于提供简洁而强大的语法&#xff0c;以支持复杂的数据检索和实时监控场景。本…

7B 开源模型突破 IMO 形式化证明,霸榜数学竞赛

总览 去年底&#xff0c;著名数学家、菲尔兹奖获得者陶哲轩就提出 AI 将加速数学研究&#xff0c;成为数学家的可靠伙伴&#xff0c;并且在形式化语言 Lean 的帮助下&#xff0c;成功证明了多项式 Freiman-Ruzsa 猜想。在今年的国际数学奥林匹克竞赛&#xff08;IMO&#xff0…

24澳中博览会|2025非洲水协年会暨展览|2025山西水展

2024澳中博览会 2025非洲水协年会暨展览 2025年山西国际水展暨水利工程设计与施工、水处理技术设备、泵管阀、智慧水务及环保展 承办单位&#xff1a;山西泽嘉国际展览有限公司 上海泽嘉展览服务有限公司 战略合作伙伴 &#xff1a; 美国迈阿密水展 欧 洲 海 水 脱 盐 淡 化…

新版Next.js 15中5个令人惊叹的特性

前端岗位内推来了 Next.js 15已经到来&#xff0c;一切比以往更好&#xff01; 从全新的编译器到700倍更快的构建时间&#xff0c;创建具有卓越性能的全栈Web应用从未如此简单。 让我们探索v15的最新特性&#xff1a; 1. create-next-app升级&#xff1a;更清晰的UI&#xff0c…

Android进程保活:如何让app一直运行

目录 1&#xff09;为什么需要进行进程保活呢&#xff1f;需求是什么&#xff1f; 2&#xff09;进程分类 3&#xff09;进程的优先级 4&#xff09;如何提高进程优先级 5&#xff09;如何进行进程保活 一、为什么需要进行进程保活呢&#xff1f;需求是什么&#xff1f; 比如…

mysql高级语句的查询语句

一、排序语法&#xff0c;关键字排序 升序和降序 默认的排序方式就是升序 升序&#xff1a;ASC 降序&#xff1a;DESC 配合语法&#xff1a;order by 语法 1、升序 select * from info order by name; 根据名字升序排序&#xff0c;不需要加ASC select * from info order…

ChinaJoy 2024,VERYCLOUD睿鸿股份与你相聚

&#x1f3ae;2024 ChinaJoy于26日正式开幕 &#x1f557;7月26-28日 &#x1f310;VERYCLOUD睿鸿股份在BTOB商务洽谈馆 &#x1f31f;W4-B785展位 &#x1f387;展台交流好礼相送 与多行业好友现场相聚、畅谈&#x1f9d0; 现场游戏企业云集 专业观众、玩家纷至沓来 与游戏/短…

配置frp实现内网穿透(.toml配置文件)

简介 frp 是一款高性能的反向代理应用&#xff0c;专注于内网穿透。它支持多种协议&#xff0c;包括 TCP、UDP、HTTP、HTTPS 等&#xff0c;并且具备 P2P 通信功能。使用 frp&#xff0c;您可以安全、便捷地将内网服务暴露到公网&#xff0c;通过拥有公网 IP 的节点进行中转。…

APACHE安装与应用

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:Linux运维老纪的首页…

乱弹篇(40)人类追求长寿

不要认为只有中国的老龄化才严重&#xff0c;实际上全球都面临老龄化&#xff0c;其中日本最为严重。 这是随着人类生活和医学水平的不断提高&#xff0c;寿命才会比过去数十年有了大幅度的提升。据资料显示&#xff0c;目前全球平均预期寿命估计为73岁。与百年之前相比&#…