linux进度条程序
文章目录
- linux进度条程序
- 两个背景知识
- 倒计时功能
- 进度条程序
- 结语
很高兴和大家见面,给生活加点impetus!!开启今天的编程之路
今天我们来学习Linux的基础构建工具,主要从是什么为什么,怎么做的角度出发,包含细节,示例
作者:٩( ‘ω’ )و260
我的专栏:Linux,C++进阶,C++初阶,数据结构初阶,题海探骊,c语言
欢迎点赞,关注!!
linux进度条程序
两个背景知识
结论1:回车换行是两个动作
平常我们写作文的时候,当我们要在下一行书写内容的时候,我们需要换行,同时,需要回车到下一行的开始。这点不多说,应该都能够理解~
所以,回车的转义字符的方式为\r,换行的转义字符的方式为\n,只不过\n其中内置了回车效果
这里我们使用两个例子来输出结论2,我们首先来看两段代码:
c语言的基本常识就为顺序结构,代码执行肯定是从上到下,此时肯定是打印了,那么打印的结果跑到哪里去了呢?
这里我也不卖关子了,这里结果其实已经是打印了,但是打印到缓冲区当中了,同时,这个缓冲区也有归属,归属于显示器。
为什么最后结果打印了呢?
答案是:归属于显示器的缓冲区其中的内容想要打印到显示器上,缓冲区必须要进行行刷新,而\n刚好就有换行的作用,所以就直接刷新到了显示器上,同时当程序运行结束的时候,显示器也会刷新。自动将其中的内容打印出来
提取结论:
缓冲区刷新方式,按照行为单位进行刷新\r\n或者\n
程序运行结束,缓冲区里的内容会被自动刷新
这里我们可以联想一个函数:IO流中的cout,作用是换行和刷新字符缓冲区,所以一定能够将缓冲区的内容打印出来~
倒计时功能
我们来完成一个代码来验证上面的结论,同时,我们也能够学到新的函数。
首先我们先来分析特点,首先因为是倒计时,而且肯定是在一个位置倒计时。我们先来看代码:
倒计时应该是在一个位置一直到0,这里的错误之处是换行了,当我们把换行去掉,再来看结果:
这个是什么原因呢?还是跟上面的结果是一样的,此时打印的结果在缓冲区中,此时缓冲区没有刷新,自然结果也就不会打印到显示屏上。
有一个函数fflush能够刷新缓存区,需要传递一个文件信息参数,在linux下,一切皆文件,当然,显示屏也是有文件的,可以理解为就是stdout:
所以我们传参就传stdout就行:
接下来我们来重新书写代码:
是不是应该8应该要替换掉9的位置,7应该要替换掉8的位置~
此时我们应该要回车,这样就能够到达这一行的开始~
所以,这里我们需要fflush和回车(\r)同时配合使用~
这里我们再来讲解一个知识点,我们来看,如果我们数字从10开始相减呢呢?
我们发现一个奇怪的现象,我们发现10后面的0没有给替换掉,只是将1给替换掉了,这里我们可以提出问题:为什么会是替换的结果?
这里我们需要提到格式化输出,格式化输入,格式化的到底是什么?
其实显示器是字符块设备,即显示器上输出的东西其实都是字符,即使我们定义了整形,但是我们其实输入的输出的都是字符,但是,保存在内存中的就是整形,所以格式化输入输出在这里的作用就是依靠ascll码进行整形和字符的转换,其余也是同理的~
在倒计时程序中,10其实是1和0字符,替换的话只是替换了1字符,0字符还保留的。所以我们这里替换两个字符,所以应该使用%2d即可:
同时,%2d默认方式是右对齐,即有字符的话在右边替换掉,左边使用空格替换,但是这里我们需要左对齐,来看代码及结果:
这样我们一个简单的倒计时程序就书写完毕,接下来我们来书写进度条程序:
进度条程序
首先进度条程序需要什么,首先,我们肯定需要进度,百分比,以及旋转轮盘,因为有了旋转轮盘,我们才能够知道这个进度条程序还在运转没有!!
我们直接来看代码:
因为有100个百分点,所以我使用100个位置,当有了一个百分点之后,同时就会输出一个等号。
为什么这里我使用’\0’来初始化processbuff数组呢?因为printf函数遇到’\0’会停止打印了。这里的usleep其实和sleep一样的,都是睡眠,差别就是usleep的参数是传递的微秒,来看结果
但是,这种进度条有没有什么实际的开发场景呢?比如说,我下载游戏,下载的过程中可以使用进度条来表明还有多久下载成功了,但是上面的代码肯定是不能代表这种场景的。
在实际下载场景中,涉及网络波动,所以进度条肯定会时快时慢,而且还应该有下载的大小,而且当网速为0或者很慢,但是仍在下载,轮盘也应该转动。此时我们直接来书写代码:
//main.c
#include"process.h"
double gtotal = 1024.0;//1024M
double speed = 1.0;//设置浮动区间使用种子函数 double speedFloat(double speed,double range)//[1,0,5.3]
{ int int_range = (int)range; return speed + rand()%int_range + (range - int_range);//记得加上小数部分
} void DownLoad(int total,callback_t cd) { srand(time(NULL)); double curr = 0; while(curr <= total) { curr += speedFloat(speed,20.3); cd(curr,total);//这里千万不能传引用,否则会造成死循环 usleep(30000); } } int main() { DownLoad(gtotal,FlushProcess); //process(); return 0; }
main.c我们使用种子函数,这样就能够生成随机数,来实现网速快慢的情况,进而模式网络波动~
而且,这里我们使用函数指针来封装进度条程序,这样能够使得更加便捷,即我们只用修改上层传入的函数,下层我们什么都不用管了。
定义格式:
typedef 返回类型(*新类型名)(参数类型)
//process.h
#pragma once #include<stdio.h> #include<unistd.h> #include<string.h> #include<time.h> #include<stdlib.h> typedef void (*callback_t)(double,double); void DownLoad(int total,callback_t cd); void process(); void FlushProcess(double curr,double total);
这里是头文件,进行声明,其中unistd.h头文件含义是unix标准,因为linux是由unix演变而来的,所以肯定会涉及一定的unix
//process.c#include"process.h"#define SIZE 101#define STYLE '='void FlushProcess(double curr,double total){if(curr > total) curr = total;//计算比率double rate = curr / total * 100;int cnt = (int)rate;char processbuff[SIZE];memset(processbuff,'\0',sizeof(processbuff));int i = 0;for(; i < cnt; i++) processbuff[i] = STYLE;static const char* label = "|/-\\";int len = strlen(label);static int index = 0;//用来标记label数组的位置printf("[%-100s][%.1lf%%][%c]\r",processbuff,rate,label[index++]);fflush(stdout);index %= len;if(curr >= total) printf("\n");}
这里是核心操作,其实细节跟我们上面讲的倒计时程序细节雷同,无非就是多了保留小数点后一位
结语
感谢大家的阅读,不足之处欢迎留言指正,感谢大家支持!!
博观而约取,厚积而薄发!!