linuxcp命令显示进度 linux 进度条
1. 前言
在之前已经了解了 【linux】vim的使用和 【linux】编译器-gcc/g++使用还有 【linux】自动化构建工具-make/makefile,有了这些工具,这次来实现一个进度条小程序。
2. 回车和换行换行:是换到新的一行。 回车:是回到最开始。
举个例子:在格子里面写字的时候,第一行写完,要到第二行,此时到的第二行的结尾,这个叫换行。而从第二行结尾回到第二行开头是回车。 也可以先回车到第一行的开始,再换行到第二行。

回车和换行是两个动作。
在老式键盘上面就很明显,而现在的键盘为了省空间就不这样了:

平时在C语言上用到的“”叫回车换行,既回车,又换行。 如果想让只回车就用到""。 有的代码用""表示回车换行,如果在""和""同时存在时,""只是换行。
在老式打字机上面就会有下面这样的拨片,当打完一行之后,得手动把它往回拨,一拨纸就往上走(换行),写入位置就往左走,对应就是回车。

在代码里面把""去掉:

在编译过程中就会发现,再休眠3秒的时候这个程序并没有输出,而是当程序结束的时候程序才输出。

加""消息就直接显示出来,然后再sleep。 不加""这个字符串打印就没有显示出来,先sleep,再到程序退出的时候才显示这个字符串。
那么在不加""那么printf和sleep哪个先运行呢? C语言在执行代码时候,默认从上往下执行,这个叫顺序结构。 printf只是没有把数据在显示器上显示出来,并不是没有执行。只是在sleep期间这个字符串没有显示出来而已。
那么在sleep期间字符串在哪里呢? 它被保存到缓冲区里面。它就是一块内存空间。 当printf的时候,把字符串拷贝到缓冲区里面,然后定期把数据刷新到显示器上面,此时就能看到这个字符串了。 不带""的时候,字符串就在缓冲区里,当return 0时,程序结束时,一般要自动冲刷缓冲区。
想要在程序结束之前就刷新缓冲区,有3种方式: 1. ""直接就把缓冲区数据就刷出来了。包含""之前的全部刷新出来。 举个例子:

会发现先出来""之前的,剩下的程序结束才出来:

2. 缓冲区满了进行刷新 3. 强制刷新。 ffush把特定文件流进行刷新:

在Linux下一切皆文件,可以把显示器当文件看。 在C语言中程序在启动时默认会打开三个输入输出流: stdin对应的设备是键盘,stdout和stderr对应的是显示器。

在系统中不管是设备还是文件一律都是FILE。 一般打印输出用到的是stdout,显示到显示器上。
为什么会默认打开这输入输出流? 方便用户进行输入和输出。一般使用计算机的都有输入和输出的需求,所以一般就默认打开输入输出流,就不用在写代码打开上面键盘和显示器这些设备了。
在代码中使用一下fflush:
代码语言:javascript代码运行次数:0运行复制 1 #include<stdio.h> 2 #include<unistd.h> 3 4 int main() 5 { 6 printf("hello world,hello..."); 7 fflush(stdout); 8 sleep(3); 9 return 0; 10 }登录后复制
编译发现缓冲区内容就直接冲刷出来了:

为什么会存在缓冲区? 缓冲区提高了用户效率。以前的printf是往硬件上写的,现在直接写到内存了。从内存拷贝内存数据的效率,肯定比从硬件拷贝到内存的效率高。 它刷新的次数越少,单次刷新的数据量越大,效率越高。 按行刷新是方便用户阅读。
4. 进度条4.1 倒计时设置假设将格子是光标的位置,一般在输入的时候就会是下面这样的:

但是如果想要实现光标在同一个位置,实现倒计时的感觉,就行下面这样:用8会覆盖这个9。

但是8会覆盖这个9后,光标会往后走,想要把在8的位置输出7,光标就得回到8的位置,7就把8覆盖,依此类推,就能实现一个动态的倒计时。 就是在同一个位置不停的覆盖,就能实现动态效果。
用代码来实现一下倒计时的感觉:

但这个代码输出并不是我们所想要的输出:

------------------------------------------------------------------------------------------
来修改一下代码,加上"":

这里发现暂停一段时间,数据并没有显示出来:

""相当于我们写了一个数回到最开始,就清了一个数,所以最后什么也不显示。
------------------------------------------------------------------------------------------
那就直接加一个强制刷新缓冲区:
代码语言:javascript代码运行次数:0运行复制 1 #include<stdio.h> 2 #include<unistd.h> 3 4 int main() 5 { 6 int count=9; 7 while(count>=0) 8 { 9 printf("%d",count); 10 fflush(stdout); 11 count--; 12 sleep(1); 13 } 14 return 0; 15 }登录后复制来看看效果:

------------------------------------------------------------------------------------------
既然能够覆盖一个字符,那么肯定也能覆盖一个字符串。
代码语言:javascript代码运行次数:0运行复制 1 #include<stdio.h> 2 #include<unistd.h> 3 4 int main() 5 { 6 int count=9; 7 while(count>=0) 8 { 9 printf("倒计时:%d",count); 10 fflush(stdout); 11 count--; 12 sleep(1); 13 } 14 printf(""); 15 return 0; 16 }登录后复制来看看效果图:

如果从10开始:

就会出现这样的效果:

数字10,实际在显示器上显示的是字符,它转化成1字符和0字符。当在打印的9时候字符长度变短了,0就没有办法覆盖,就会一直在。 所以这里用%2d:

这时候就没有问题了:

这里用多文件来实现,Processbar.h用来声明,Processbar.c用来实现方法,Main.c用来调用Processbar.c里面的方法,再使用Makefile来实现自动化调用。

先写出基本的框架逻辑:

在编译的时候不用.h文件,因为在.c文件中已经包含.h是在当前目录下的,在编译时候会展开头文件的。 在Makefile里面写:
代码语言:javascript代码运行次数:0运行复制1 processbar:Main.c Processbar.c 2 gcc -o $@ $^ 3 .PHONY:clean 4 clean: 5 rm -f processbar登录后复制登录后复制
测试一下代码:

先画出进度条的示例: 进度条在增加的同时,当前的进度也在变化,光标也在不停的旋转。

这个进度条实现的时候,缓冲区的长度从0%到100%,但是还得考虑"",所以长度定义为101。 把缓冲区清空就用到memset。

想要在缓冲区里面写特殊符号,就直接用define:#define Style '#'。
用循环来实现动态进度条打印,直接打印相对应的字符串,和倒计时一样用fflush(stdout);来刷新缓冲区,随着时间的增加,进度条也在不断增加:

来看看效果:

发现这里打印时间太慢了。
使用usleep,它休眠的时间比sleep的小,所以这里就用usleep来进行休眠。

然后将字符串输出改为左对齐,加上进度条对应的比率:

来看看效果:

但是一般进度条不会单独出现,只有当我们下载一个文件同时出现。 这里就先模拟下载过程,就在在Main.c写一个download来实现。一般在下载一个文件的时候,会有下载文件的大小和下载到多少,和网络的带宽。 分别用变量定义一下文件大小,当前下载进度和带宽:
代码语言:javascript代码运行次数:0运行复制double filesize = 1024*1024*1024*1.0;double current = 0.0; double bandwidth = 1024*1024*1.0;登录后复制
还可以加上一个开始下载的提示:
代码语言:javascript代码运行次数:0运行复制printf("download begin,current: %lf",current);登录后复制和下载完成的提示:
代码语言:javascript代码运行次数:0运行复制printf("download done,filesize: %lf",filesize);登录后复制在下载过程中把要下载的文件大小,和目前已经下载的大小传给进度条ProcBar,让进度条时时交互。
在Processbar.h中记得把在Processbar.c使用的打印进度条函数声明一下:
代码语言:javascript代码运行次数:0运行复制void ProcBar(double total,double current);登录后复制
在Processbar.c中,就和上面的简单实现进度条一样,把文件的长度,和目前下载的长度传进去:
代码语言:javascript代码运行次数:0运行复制void ProcBar(double total,double current)登录后复制
这里加了当前下载的进度百分比 double rate=(current*100.0)/total; 在循环的时候得将前下载的进度输出,循环的时候得把double rate的类型转为int:
代码语言:javascript代码运行次数:0运行复制int loop_count=(int)rate;登录后复制
最后打印出当前下载的进度,还得冲刷缓冲区:
代码语言:javascript代码运行次数:0运行复制 printf("[%-100s][%.1lf%%][%c]",bar,rate,lable[cnt%len]); fflush(stdout);登录后复制来看看效果

在Processbar.h中定义一个函数指针类型:
代码语言:javascript代码运行次数:0运行复制typedef void(*callback_t)(double,double);登录后复制
然后在Main.c里面将download改一下,可以根据文件的大小来下载:
代码语言:javascript代码运行次数:0运行复制void download(double filesize,callback_t cb)登录后复制
在download函数里面直接执行:cb(filesize,current);方法。 为什么要这么写? 在之后如果用户写一个图形化界面的进度条,就能在下载的时候同时更新图形化界面。
也可以让进度条加上颜色,只需要在网上找一个关于用C语言输出有颜色相关的内容也就会有了。 这里是加了颜色效果:
代码语言:javascript代码运行次数:0运行复制 printf("[40;44m[%-100s][%.1lf%%][%c][0m",bar,rate,lable[cnt%len]);登录后复制

1 #pragma once 2 3 #include<stdio.h> 4 5 typedef void(*callback_t)(double,double); 6 void ProcBar(double total,double current); 7 //extern void ForTest();登录后复制5.2 Processbar.c代码语言:javascript代码运行次数:0运行复制
1 #include "Processbar.h" 2 #include登录后复制5.3 Main.c代码语言:javascript代码运行次数:0运行复制3 #include 4 5 #define Length 101 6 #define Style '#' 7 8 const char *lable = "|/-\"; 9 10 11 void ProcBar(double total,double current) 12 { 13 char bar[Length]; 14 memset(bar,'',sizeof(bar)); 15 int len=strlen(lable); 16 17 int cnt = 0; 18 double rate=(current*100.0)/total; 19 int loop_count=(int)rate; 20 while(cnt<=loop_count) 21 { 22 bar[cnt++]=Style; 23 24 } 25 26 //没有加颜色前的输出 printf("[%-100s][%.1lf%%][%c]",bar,rate,lable[cnt%len]); printf("[40;44m[%-100s][%.1lf%%][%c][0m",bar,rate,lable[cnt%len]); 27 fflush(stdout); 28 }
1 #include"Processbar.h" 2 #include登录后复制5.4 Makefile代码语言:javascript代码运行次数:0运行复制3 4 double bandwidth = 1024*1024*1.0; 5 void download(double filesize,callback_t cb) 6 { 7 double current = 0.0; 8 9 10 printf("download begin,current: %lf",current); 11 while(current<=filesize) 12 { 13 cb(filesize,current); 14 usleep(100000); 15 current+=bandwidth; 16 17 } 18 printf("download done,filesize: %lf",filesize); 19 } 20 21 22 int main() 23 { 24 download(101*1024*1024,ProcBar); 25 // ProcBar(100.0,56.9); 26 27 // ProcBar(100.0,1.0); 28 // ProcBar(100.0,99.9); 29 30 // ProcBar(100.0,100); 31 //ForTest(); 32 return 0; 33 }~
1 processbar:Main.c Processbar.c 2 gcc -o $@ $^ 3 .PHONY:clean 4 clean: 5 rm -f processbar登录后复制登录后复制
有问题请指出,大家一起进步吧!!!
以上就是【Linux】实现进度条小程序的详细内容,更多请关注乐哥常识网其它相关文章!
