0

0

【Linux】实现进度条小程序

蓮花仙者

蓮花仙者

发布时间:2025-07-21 09:46:22

|

394人浏览过

|

来源于php中文网

原创

1. 前言

在之前已经了解了 【linux】vim的使用和 【linux】编译器-gcc/g++使用还有 【linux】自动化构建工具-make/makefile,有了这些工具,这次来实现一个进度条小程序。

2. 回车和换行

换行:是换到新的一行。 回车:是回到最开始。

举个例子:在格子里面写字的时候,第一行写完,要到第二行,此时到的第二行的结尾,这个叫换行。而从第二行结尾回到第二行开头是回车。 也可以先回车到第一行的开始,再换行到第二行。

【Linux】实现进度条小程序

回车和换行是两个动作。

在老式键盘上面就很明显,而现在的键盘为了省空间就不这样了:

【Linux】实现进度条小程序

平时在C语言上用到的“\n”叫回车换行,既回车,又换行。 如果想让只回车就用到"\r"。 有的代码用"\r\n"表示回车换行,如果在"\r""\n"同时存在时,"\n"只是换行。

在老式打字机上面就会有下面这样的拨片,当打完一行之后,得手动把它往回拨,一拨纸就往上走(换行),写入位置就往左走,对应就是回车。

【Linux】实现进度条小程序
3. 缓冲区

在代码里面把"\n"去掉:

【Linux】实现进度条小程序

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

【Linux】实现进度条小程序

"\n"消息就直接显示出来,然后再sleep。 不加"\n"这个字符串打印就没有显示出来,先sleep,再到程序退出的时候才显示这个字符串。

那么在不加"\n"那么printfsleep哪个先运行呢? C语言在执行代码时候,默认从上往下执行,这个叫顺序结构。 printf只是没有把数据在显示器上显示出来,并不是没有执行。只是在sleep期间这个字符串没有显示出来而已。

那么在sleep期间字符串在哪里呢? 它被保存到缓冲区里面。它就是一块内存空间。 当printf的时候,把字符串拷贝到缓冲区里面,然后定期把数据刷新到显示器上面,此时就能看到这个字符串了。 不带"\n"的时候,字符串就在缓冲区里,当return 0时,程序结束时,一般要自动冲刷缓冲区。

想要在程序结束之前就刷新缓冲区,有3种方式: 1. "\n"直接就把缓冲区数据就刷出来了。包含"\n"之前的全部刷新出来。 举个例子:

【Linux】实现进度条小程序

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

【Linux】实现进度条小程序

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

【Linux】实现进度条小程序

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

【Linux】实现进度条小程序

在系统中不管是设备还是文件一律都是FILE。 一般打印输出用到的是stdout,显示到显示器上。

为什么会默认打开这输入输出流? 方便用户进行输入和输出。一般使用计算机的都有输入和输出的需求,所以一般就默认打开输入输出流,就不用在写代码打开上面键盘和显示器这些设备了。

在代码中使用一下fflush

代码语言:javascript代码运行次数:0运行复制
  1 #include  2 #include  3  4 int main()  5 {  6   printf("hello world,hello...");  7   fflush(stdout);  8   sleep(3);  9   return 0; 10 }
【Linux】实现进度条小程序

编译发现缓冲区内容就直接冲刷出来了:

【Linux】实现进度条小程序

为什么会存在缓冲区? 缓冲区提高了用户效率。以前的printf是往硬件上写的,现在直接写到内存了。从内存拷贝内存数据的效率,肯定比从硬件拷贝到内存的效率高。 它刷新的次数越少,单次刷新的数据量越大,效率越高。 按行刷新是方便用户阅读。

4. 进度条4.1 倒计时设置

假设将格子是光标的位置,一般在输入的时候就会是下面这样的:

【Linux】实现进度条小程序

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

【Linux】实现进度条小程序

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

用代码来实现一下倒计时的感觉:

【Linux】实现进度条小程序

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

【Linux】实现进度条小程序

------------------------------------------------------------------------------------------

HiShop网店代理分销系统
HiShop网店代理分销系统

Hishop.5.2.BETA2版主要更新: [修改] 进一步优化了首页打开速度 [修改] 美化了默认模板 [修改] 优化系统架构,程序标签及SQL查询效率,访问系统页面的速度大大提高 [修改] 采用了HTML模板机制,实现了前台模板可视化编辑,降低模板制作与修改的难度. [修改] 全新更换前后台AJAX技术框架,提升了用户操作体验. 店铺管理 [新增] 整合TQ在线客服 [修改] 后台广告位增加

下载

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

【Linux】实现进度条小程序

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

【Linux】实现进度条小程序

"\r"相当于我们写了一个数回到最开始,就清了一个数,所以最后什么也不显示。

------------------------------------------------------------------------------------------

那就直接加一个强制刷新缓冲区:

代码语言:javascript代码运行次数:0运行复制
  1 #include  2 #include  3  4 int main()  5 {  6   int count=9;  7   while(count>=0)  8   {  9     printf("%d\r",count); 10     fflush(stdout); 11     count--; 12     sleep(1); 13   } 14   return 0; 15 }

来看看效果:

【Linux】实现进度条小程序

------------------------------------------------------------------------------------------

既然能够覆盖一个字符,那么肯定也能覆盖一个字符串。

代码语言:javascript代码运行次数:0运行复制
  1 #include  2 #include  3  4 int main()  5 {  6   int count=9;  7   while(count>=0)  8   {  9     printf("倒计时:%d\r",count); 10     fflush(stdout); 11     count--; 12     sleep(1); 13   } 14   printf("\n"); 15   return 0; 16 }

来看看效果图:

【Linux】实现进度条小程序

如果从10开始:

【Linux】实现进度条小程序

就会出现这样的效果:

【Linux】实现进度条小程序

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

【Linux】实现进度条小程序

这时候就没有问题了:

【Linux】实现进度条小程序
4.2 进度条

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

【Linux】实现进度条小程序

先写出基本的框架逻辑:

【Linux】实现进度条小程序

在编译的时候不用.h文件,因为在.c文件中已经包含.h是在当前目录下的,在编译时候会展开头文件的。 在Makefile里面写:

代码语言:javascript代码运行次数:0运行复制
  1 processbar:Main.c Processbar.c  2   gcc -o $@ $^   3 .PHONY:clean  4 clean:  5   rm -f processbar

测试一下代码:

【Linux】实现进度条小程序
4.2.1 实现简单进度条

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

【Linux】实现进度条小程序

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

【Linux】实现进度条小程序

想要在缓冲区里面写特殊符号,就直接用define:#define Style '#'

用循环来实现动态进度条打印,直接打印相对应的字符串,和倒计时一样用fflush(stdout);来刷新缓冲区,随着时间的增加,进度条也在不断增加:

【Linux】实现进度条小程序

来看看效果:

【Linux】实现进度条小程序

发现这里打印时间太慢了。

使用usleep,它休眠的时间比sleep的小,所以这里就用usleep来进行休眠。

【Linux】实现进度条小程序

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

【Linux】实现进度条小程序

来看看效果:

【Linux】实现进度条小程序
4.2.2 进度条完善

但是一般进度条不会单独出现,只有当我们下载一个文件同时出现。 这里就先模拟下载过程,就在在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\n",current);

和下载完成的提示:

代码语言:javascript代码运行次数:0运行复制
printf("\ndownload done,filesize: %lf\n",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]\r",bar,rate,lable[cnt%len]);  fflush(stdout);

来看看效果

【Linux】实现进度条小程序

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("\033[40;44m[%-100s][%.1lf%%][%c]\r\033[0m",bar,rate,lable[cnt%len]);
【Linux】实现进度条小程序
【Linux】实现进度条小程序
5. 附进度条代码5.1 Processbar.h代码语言:javascript代码运行次数:0运行复制
  1 #pragma once  2  3 #include  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   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,'\0',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]\r",bar,rate,lable[cnt%len]);        printf("\033[40;44m[%-100s][%.1lf%%][%c]\r\033[0m",bar,rate,lable[cnt%len]); 27     fflush(stdout); 28 }
5.3 Main.c代码语言:javascript代码运行次数:0运行复制
  1 #include"Processbar.h"  2 #include   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\n",current); 11   while(current<=filesize) 12   { 13     cb(filesize,current); 14     usleep(100000); 15     current+=bandwidth; 16 17   } 18   printf("\ndownload done,filesize: %lf\n",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 }~
5.4 Makefile代码语言:javascript代码运行次数:0运行复制
  1 processbar:Main.c Processbar.c  2   gcc -o $@ $^   3 .PHONY:clean  4 clean:  5   rm -f processbar

有问题请指出,大家一起进步吧!!!

相关专题

更多
C语言变量命名
C语言变量命名

c语言变量名规则是:1、变量名以英文字母开头;2、变量名中的字母是区分大小写的;3、变量名不能是关键字;4、变量名中不能包含空格、标点符号和类型说明符。php中文网还提供c语言变量的相关下载、相关课程等内容,供大家免费下载使用。

395

2023.06.20

c语言入门自学零基础
c语言入门自学零基础

C语言是当代人学习及生活中的必备基础知识,应用十分广泛,本专题为大家c语言入门自学零基础的相关文章,以及相关课程,感兴趣的朋友千万不要错过了。

618

2023.07.25

c语言运算符的优先级顺序
c语言运算符的优先级顺序

c语言运算符的优先级顺序是括号运算符 > 一元运算符 > 算术运算符 > 移位运算符 > 关系运算符 > 位运算符 > 逻辑运算符 > 赋值运算符 > 逗号运算符。本专题为大家提供c语言运算符相关的各种文章、以及下载和课程。

354

2023.08.02

c语言数据结构
c语言数据结构

数据结构是指将数据按照一定的方式组织和存储的方法。它是计算机科学中的重要概念,用来描述和解决实际问题中的数据组织和处理问题。数据结构可以分为线性结构和非线性结构。线性结构包括数组、链表、堆栈和队列等,而非线性结构包括树和图等。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

257

2023.08.09

c语言random函数用法
c语言random函数用法

c语言random函数用法:1、random.random,随机生成(0,1)之间的浮点数;2、random.randint,随机生成在范围之内的整数,两个参数分别表示上限和下限;3、random.randrange,在指定范围内,按指定基数递增的集合中获得一个随机数;4、random.choice,从序列中随机抽选一个数;5、random.shuffle,随机排序。

600

2023.09.05

c语言const用法
c语言const用法

const是关键字,可以用于声明常量、函数参数中的const修饰符、const修饰函数返回值、const修饰指针。详细介绍:1、声明常量,const关键字可用于声明常量,常量的值在程序运行期间不可修改,常量可以是基本数据类型,如整数、浮点数、字符等,也可是自定义的数据类型;2、函数参数中的const修饰符,const关键字可用于函数的参数中,表示该参数在函数内部不可修改等等。

525

2023.09.20

c语言get函数的用法
c语言get函数的用法

get函数是一个用于从输入流中获取字符的函数。可以从键盘、文件或其他输入设备中读取字符,并将其存储在指定的变量中。本文介绍了get函数的用法以及一些相关的注意事项。希望这篇文章能够帮助你更好地理解和使用get函数 。

640

2023.09.20

c数组初始化的方法
c数组初始化的方法

c语言数组初始化的方法有直接赋值法、不完全初始化法、省略数组长度法和二维数组初始化法。详细介绍:1、直接赋值法,这种方法可以直接将数组的值进行初始化;2、不完全初始化法,。这种方法可以在一定程度上节省内存空间;3、省略数组长度法,这种方法可以让编译器自动计算数组的长度;4、二维数组初始化法等等。

601

2023.09.22

Java JVM 原理与性能调优实战
Java JVM 原理与性能调优实战

本专题系统讲解 Java 虚拟机(JVM)的核心工作原理与性能调优方法,包括 JVM 内存结构、对象创建与回收流程、垃圾回收器(Serial、CMS、G1、ZGC)对比分析、常见内存泄漏与性能瓶颈排查,以及 JVM 参数调优与监控工具(jstat、jmap、jvisualvm)的实战使用。通过真实案例,帮助学习者掌握 Java 应用在生产环境中的性能分析与优化能力。

19

2026.01.20

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Swoft2.x速学之http api篇课程
Swoft2.x速学之http api篇课程

共16课时 | 0.9万人学习

PHP基础入门课程
PHP基础入门课程

共33课时 | 2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号