一、前言
在 Linux 上写下一个简易的进度条小程序。
成品展示:
今天的内容比较轻松,只需要了解两个知识点,这个小程序就很容易写出来了,让我们开始今天的学习。
二、理解 ‘ ’ 与 ‘ ’
C 语言中有很多字符,而字符大体分为两类:可显字符、控制字符。
控制字符不可显示,例如 和 就是控制字符。
而在我们平时打字时,一行写满了需要换行,但是新起一行有很多种,例如:
这样虽然新起一行了,但是不是我们想要的结果。
我们通常新起一行是在第二行的最左端,但是对于这个结果其实有两个操作:
1.跳转到第二行
2.回到第二行的最左端
有了这个基本概念,再来谈 和 的作用:
:回车 - 回到文本行的开头
:换行 - 新起一行
所以,其实我们平时泛指的换行实际上是 回车 + 换行。
且在语言范畴下,例如 C 语言,换行就可以达到回车 + 换行的效果。在平常,这一操作还是两个步骤。
三、行缓冲
行缓冲这个概念认识。
1、提出问题
首先先了解一下两个库函数:
sleep:Linux 下的休眠函数,单位是秒。头文件为#include
fflush:刷新缓冲区
代码 1:
#includeintmain() { printf("helloxxx"); sleep(3); return0; }
现象:
分析:
光标停留在文本行的开头,但是字符串没有被打印。
反而像是 sleep 函数先起作用,然后 printf 函数再从光标处开始打印。
打印完之后,shell 提示符紧跟着字符串后显示。
代码 2:
#includeintmain() { printf("helloxxx "); sleep(3); return0; }
现象:
分析:
printf 打印的字符串先显示在终端上,光标位于字符串的下一行。
sleep 函数使程序休眠 3 秒后,shell 提示符从光标位置开始显示。
代码 3:
#includeintmain() { printf("helloxxx "); sleep(3); return0; }
现象:
分析:
printf 打印的字符串没有显示到终端,光标一直停留在该打印字符串的一行
sleep 函数休眠三秒后,shell 提示符直接打印在了屏幕上。并没有看到字符串。
观察上面的现象,我们提出几个问题:
代码 1 好像是先执行了 sleep ,在执行 printf ,是这样吗?
代码 2 加上了 ‘ ’ ,字符串一开始就显示了,为什么?
代码 3 好像什么都没打印,这是为什么?
在解答这些问题之后,我们先了解一下行缓冲。
2、认识行缓冲
在内存中预留了一块空间,用来缓冲输入或输出的数据,这个保留的空间被称为缓冲区。
我们之前或多或少都听说过缓冲区。
在代码 1 中,由于程序是按照数据执行的,所以必定是先执行 printf 。
但是数据没有显示,所以这时候,数据就一定被保存在某个位置,保存的位置就是缓冲区。
而要让数据显示,是需要刷新缓冲区的。
行缓冲是缓冲区刷新策略的一种,在行缓冲模式下,当输入和输出中遇到 ‘ ’ 换行时,就会刷新缓冲区。
有了这个概念,我们继续分析问题。
3、解答与拓展
解答:
问题 1:代码 1 好像是先执行了 sleep ,在执行 printf ,是这样吗?
当然不是。由于程序是按照顺序执行的,所以必定是先执行完 printf 在执行 sleep 。
而数据没有被显示出来的原因是:数据保存在缓冲区中,但是没有主动刷新,当程序退出后,保存在缓冲区中的数据被自动刷新出来了。
所以才会造成这种现象。
问题 2:代码 2 加上了 ,字符串一开始就显示了,为什么?
这里由于是直接往显示器上打印,所以采用的刷新方式为行缓冲。
所以执行碰到 ‘ ’ 时,就会把在缓冲区中的 (换行符之前) 的内容全部刷新出来。
所以这段代码一开始就会有数据显示,然后再 sleep 休眠。
问题 3:代码 3 好像什么都没打印,这是为什么?
之前说过 是换行,所以当 printf 遇到 时,就把光标移到开头。sleep 睡眠后,当程序退出,shell 打印提示符时,就覆盖了字符串。
拓展:
数据真的是临时保留在缓冲区里的吗?光标如何理解?
我们用一段代码来理解这两个问题:
#include#include intmain() { printf("helloxxx "); fflush(stdout); sleep(3); return0; }
现象:
观察现象,我们发现当我们使用fflush主动刷新缓冲区后,数据就显示在了屏幕上;且因为 ‘ ’ 的原因,光标指向字符串开头;当打印 shell 提示符时,就直接从光标位置开始覆盖。
所以对于这两个问题,我们已经得到了答案:
1.数据被临时保存在于缓冲区中,通过刷新就可以显示
2.数据是从光标位置开始打印的。
一句话理解光标:光标和显示器匹配,光标在哪里,显示器打印的时候就从哪里开始打印。
4、倒计时
基于对上面的理解,我们先实现一个简单的倒计时。
倒计时就是在屏幕上不断显示数字,每次在同一位置显示,并将之前的数据覆盖。
既然是每次要从头开始覆盖,那么就可以用 ‘ ’ 来实现每次回到行首,并且可以通过相应的格式化控制显示多位打印。
但是 ‘ ’ 不会主动刷新,所以要用fflush函数主动刷新缓冲区。
在每次刷新之后,使用 sleep 函数,间隔一定的时间。
由此,我们可以很轻松写出代码,例如写一个从 10 开始的倒计时:
#include#include intmain() { inti=10; for(;i>=0;i--){ //位宽控制, 回到开头 printf("%2d ",i); fflush(stdout);//主动刷新 sleep(1);//休眠 } printf(" ");//换行,打印提示符 return0; }
四、进度条
好了,接下来进入正题,我们开始写进度条。
进度条样式:
主体样式为两个中括号包裹,中间=>推进的方式呈现,比如:[======>]
主体右侧中括号位置保持不变,中间元素不断推进,比如:[=> ]
显示当前加载进度,用[num%]显示,num 随着进度条的不断推进而变化
显示加载样式,可以利用一个旋转的字符,例如[]的样式,顺时针不断旋转
大约呈现状态为:[========>] [15%] []
采用多文件:
文件存放在proc目录中
proc.h :函数声明
proc.c :进度条逻辑
main.c :函数调用
makefile准备:
由于采用多文件,所以依赖关系可以写成依赖文件列表的样式:
分块逻辑:
1.进度条主体
预留进度条大小为 100 个=,外加 1 个>,加上保存'�'的位置,用数组存储为 102 个单位。
进度条是一行中的,所以需要用到' ',每次都需要使用fllush主动刷新缓冲区。
每次刷新出数据之后,将 = 填充到数组中,并且显示 > 。在最后一次显示时,控制 > 不要显示。
然后休眠一小会。由于休眠用 sleep 函数太慢。所以可以用 usleep 函数休眠,usleep 函数的参数单位是微秒。
根据这个写出代码:
2.百分比显示
%% 显示为一个 % ,而 %d 为数字,这步很简单,只要在 printf 语句中加上内容:
printf("[%-100s][%d%%] ",bar,i);
3.旋转光标:
光标旋转方向为顺时针旋转,那么旋转时就可以用数组保存。
旋转每次显示内容分别为| / - ,\代表一个 ,因为和 结合的会被解析为转义字符,将其保存到字符串中。
而由于字符串一共就四个字符,所以输出的时候需要控制输出位置。
代码:
constchar*str="|/-";//字符串 printf("[%-100s][%d%%][%c] ",bar,i,str[i%4]);//输出语句
完整代码:
proc.h:
#pragmaonce #includeexternvoidprocess();
proc.c:
#include"proc.h" #include#include #defineSIZE102//数组大小 #defineSTYLE'=' #defineFLAG'>' voidprocess() { constchar*str="|/-"; charbar[SIZE]; memset(bar,'�',sizeof(bar)); inti=0; while(i<= 100) { printf("[%-100s][%d%%][%c] ", bar, i, str[i % 4]); // 格式控制 fflush(stdout); // 刷新 bar[i++] = STYLE; // 填充数据 if (i != 100) { bar[i] = FLAG; // 如果不是最后一次则显示 > } usleep(100000);//休眠 } printf(" "); }
test.c
#include"proc.h" intmain() { process(); return0; }
进度条展示:
-
Linux
+关注
关注
87文章
11292浏览量
209332 -
C语言
+关注
关注
180文章
7604浏览量
136694 -
字符
+关注
关注
0文章
233浏览量
25199 -
函数
+关注
关注
3文章
4327浏览量
62573 -
小程序
+关注
关注
1文章
234浏览量
12126
原文标题:教你在 Linux 上写一个进度条小程序
文章出处:【微信号:良许Linux,微信公众号:良许Linux】欢迎添加关注!文章转载请注明出处。
发布评论请先 登录
相关推荐
评论