??作者:小樹苗渴望變成參天大樹
??作者宣言:認(rèn)真寫好每一篇博客
??作者gitee:gitee
??作者專欄:C語言,數(shù)據(jù)結(jié)構(gòu)初階,Linux,C++ 動(dòng)態(tài)規(guī)劃算法
如 果 你 喜 歡 作 者 的 文 章 ,就 給 作 者 點(diǎn) 點(diǎn) 關(guān) 注 吧!
前言
大家好久不見,已經(jīng)快一個(gè)月沒有更新Linux相關(guān)的知識(shí)了,希望大家還沒有忘記前面學(xué)過的知識(shí),不記得可以看看我前面寫的博客,可以快速幫大家進(jìn)行回憶,今天我們講講一個(gè)新的知識(shí),把我們前面說到的make進(jìn)行聯(lián)系起來,再講小程序進(jìn)度條之前,我還有兩個(gè)知識(shí)鋪墊,不然大家不好理解,話不多說,我們開始進(jìn)入正文
一、知識(shí)鋪墊
再講解進(jìn)度條之前,我們必須了解這兩個(gè)概念,一個(gè)是回車換行,一個(gè)是行緩沖區(qū)
1.1回車換行
對(duì)于回車換行其實(shí)是兩個(gè)概念,一個(gè)是回車,一個(gè)是換行,換行是光標(biāo)換到下一行,并不會(huì)到文本的開頭,回車使光標(biāo)回到當(dāng)前行的開始,那在我們語言的層面是怎么做到對(duì)文本進(jìn)行換行和回車的,我們平時(shí)說到 \n其實(shí)就是換行的意思的,但是語言的本身把他解釋成回車換行,\r是回車的意思的,回車換行其實(shí)就是先換行再進(jìn)行回車,我們來看看老式的鍵盤
這個(gè)標(biāo)志就很形象,為什么要講解這個(gè)知識(shí)點(diǎn),原因是為了更好的引出下面這個(gè)要鋪墊的知識(shí)點(diǎn)
1.2行緩沖區(qū)
再我們的C語言中,我們要行緩沖區(qū),這是個(gè)什么,為什么要有這個(gè),再我們運(yùn)行程序的時(shí)候,我們會(huì)在屏幕上看到顯示的內(nèi)容,這些都是由字符組成的,那我們的C語言不是一個(gè)字符一個(gè)字符的顯示再屏幕上,這樣覺得消耗太大了,所以我們有了行緩沖區(qū)的概念,就是程序運(yùn)行時(shí)的一塊內(nèi)存,把數(shù)據(jù)先放到這個(gè)內(nèi)存里面,等到這個(gè)小內(nèi)存滿了,就直接一起全部給刷新出來,為什么又叫行緩沖區(qū),就是當(dāng)一行滿了,就一起刷新出來,只有遇到\n或者scanf或者fflush這樣的函數(shù)就會(huì)提前進(jìn)行刷新,程序結(jié)束后,最終也會(huì)將數(shù)據(jù)進(jìn)行刷新出來。
所以我們來看一個(gè)例子:
#include <stdio.h>
#include<unistd.h>
int main()
{
printf("hello Makefile!\n");
sleep(3);
return 0;
}
再來看這個(gè)代碼:
#include <stdio.h>
#include<unistd.h>
int main()
{
printf("hello Makefile!");//1
sleep(3);//2
return 0;
}
大家看到這個(gè)結(jié)果大概率會(huì)認(rèn)為先執(zhí)行了2代碼,再執(zhí)行1代碼,但是事實(shí)卻不是這個(gè)樣子的,我們C語言的代碼都是自上往下進(jìn)行執(zhí)行的,除非遇到跳轉(zhuǎn),循環(huán)之類的,對(duì)于上面的代碼的肯定是先執(zhí)行的打印函數(shù),再執(zhí)行休眠函數(shù),那為什么不是先打印出來呢??原因就是,打印的數(shù)據(jù)再緩沖區(qū)里面,然后開始執(zhí)行了2代碼,最后程序結(jié)束了,就會(huì)一起刷新出來,最后從顯示出來。
我們想必須提前刷新出來,還有一種方法就是使用fflush函數(shù),我們查看一下手冊(cè)
再我們c語言會(huì)默認(rèn)打開三個(gè)流,這個(gè)再C語言專欄的文件操作講過,一個(gè)是輸入流stdin,一個(gè)是輸出流stdout,一個(gè)是錯(cuò)誤流stderr,而fflush的參數(shù)就是傳流進(jìn)出,這里是將數(shù)據(jù)輸出,所以使用輸出流
代碼修改:
#include <stdio.h>
#include<unistd.h>
int main()
{
printf("hello Makefile!");
fflush(stdout);
sleep(3);
return 0;
}
大家看到達(dá)到我們想要的效果了吧。
1.3倒計(jì)時(shí)
結(jié)合上面講的兩個(gè)知識(shí)點(diǎn),進(jìn)行編寫一個(gè)倒計(jì)時(shí)。
1 #include"processBar.h"
2 int main()
3
4 {
5 int cnt=9;
6 while(cnt>=0)
7 {
8 printf("%d",cnt);
9 fflush(stdout); //不加會(huì)顯示不出來,最后會(huì)一起顯示出來
10 sleep(1);
11 cnt--;
12 }
13 return 0;
14 }
不加:
加:
顯然這兩種都不是我們想要的倒計(jì)時(shí),我們看看有一個(gè)特點(diǎn),我們每輸出一個(gè)時(shí)間光標(biāo)就往后面跑一個(gè)字符,所以想要把之前的字符覆蓋,就要是光標(biāo)一直再開頭的位置,所以我們?cè)俅蛴〉臅r(shí)候加一個(gè) \r
+\r
這才是我們想要的倒計(jì)時(shí),但是這個(gè)程序還有一個(gè)小毛病,但從大于9開始倒計(jì)時(shí)就會(huì)出現(xiàn)問題,我們需要進(jìn)行打印格式的調(diào)整
會(huì)出現(xiàn)下面的情況:
解決方法:(以%-2d的形式進(jìn)行打印就可以了)
到這里我們的知識(shí)鋪墊到此結(jié)束,接下來開始正式講解進(jìn)度條的實(shí)現(xiàn)
二、進(jìn)度條
我們最終是要將我們的進(jìn)度條模擬實(shí)現(xiàn)成多軟件一起下載的場(chǎng)景,如下:
此次進(jìn)度條的模擬實(shí)現(xiàn),我打算使用多文件的方式,使用自動(dòng)化構(gòu)建來編寫,我們開始做一些前期工作
我們準(zhǔn)備工作做好之后,我們開始來實(shí)現(xiàn)進(jìn)度條代碼吧
2.1基礎(chǔ)進(jìn)度條
設(shè)計(jì)思想: 在實(shí)現(xiàn)對(duì)多軟件的模擬進(jìn)度條下載,我們必須先弄清楚一個(gè)普通的進(jìn)度條是怎么實(shí)現(xiàn)的吧。我們就需要使用到\r的特性,\r是回車的意思,將光標(biāo)回到當(dāng)前行開始的地方,我們采取的是先打印一個(gè)字符,然后再增加一個(gè)字符進(jìn)行覆蓋打印,如果是換行打印,就類似于一個(gè)直角三角形,我們來看代碼實(shí)例:
-
錯(cuò)誤示范
這個(gè)顯然不是我們想要的效果,我們達(dá)到我們想要的推進(jìn)式打印,但是想要打印在同一行,這時(shí)候就需要使用\r使光標(biāo)變到第一行,然后一次一次的覆蓋打印,但是要記得刷新。 -
正確操作
這個(gè)就符合我們想要的進(jìn)度條了,但是這個(gè)進(jìn)度條和我們一開始想要的還是有差別 -
將進(jìn)度條放在一個(gè)框框里面,并且顯示進(jìn)度,這個(gè)需要了解C語言的打印格式,C語言默認(rèn)是右對(duì)齊,我們想要每次打印從左往右,就需要采取左對(duì)齊,再框框里面預(yù)留100個(gè)位置,因?yàn)橐淮问窃黾右粋€(gè)字符,我們來看代碼:
-
等待旋轉(zhuǎn)標(biāo)志
這個(gè)是告訴用戶進(jìn)度條再運(yùn)行,給個(gè)提示,使用字符 **|/-\**循環(huán)打印來模擬實(shí)現(xiàn)再旋轉(zhuǎn)的場(chǎng)景,看代碼:
我們的第一代進(jìn)度條就算是完成了,我們?cè)賮硗晟埔幌?,使他變得可控一?br>
代碼:
1 #include"processbar.h"
2 void processbar()
3 {
4 char bar[NUM]={0};
5 int cnt=0;
6 const char*label="|/-\\";
7 int len=strlen(label);
8 while(cnt<=100)
9 {
10 printf("[%-100s][%d%%][%c]\r",bar,cnt,label[cnt%len]);
11 fflush(stdout);
12 usleep(50000);//控制進(jìn)度條的時(shí)間
13 bar[cnt++]=STYLE;
14 }
15 printf("\n");
16 }
2.2進(jìn)階進(jìn)度條
我們要是想完成這個(gè)進(jìn)階進(jìn)度條,就不能把循環(huán)放進(jìn)一個(gè)函數(shù)里面,這樣是不可控的,我們要專門寫一個(gè)下載函數(shù),來進(jìn)行軟件的下載,把下載的進(jìn)度單獨(dú)設(shè)置成一個(gè)函數(shù),什么叫下載的進(jìn)度,下面這就叫下載的進(jìn)度
我們來修改代碼:
1 #include"processbar.h"
2
3 //下載函數(shù)
4 void download(int tatol,int internetspeep)//傳軟件總大小和下載速度
5 {
6 initbar();
7 int cur=0;//從0MB開始下載
8 while(cur<=tatol)
9 {
10 processbar(cur*100/tatol,tatol,internetspeep);//乘100是因?yàn)閭鬟M(jìn)去里面有百分比,傳當(dāng)前進(jìn)度,總大小和下載速度
11 cur+=internetspeep;//internetspeepMB/s的速度下載
12 usleep(1000000);
13 }
14 printf("\n");
15 }
16 //進(jìn)度函數(shù)
17 char bar[NUM]={0};//設(shè)置成全局的,因?yàn)樵傧螺d函數(shù)里面要頻繁調(diào)用進(jìn)度函數(shù),而進(jìn)度是一直推進(jìn)的,放在進(jìn)度函數(shù)里面會(huì)導(dǎo)致調(diào)用依次之后就會(huì)被銷毀
18 void initbar()//每次任務(wù)下載的之前都要初始化一下
19 {
20 memset(bar,'\0',sizeof(bar));
21 }
22 void processbar(int rate,int tatol,int internetspeep)//傳當(dāng)前進(jìn)度進(jìn)來,就是已經(jīng)下載的大小占總大小的多少
23 {
24 const char*label="|/-\\";
25 int len=strlen(label);
26 printf("[%-100s][%d%%][%c][%s%d%s]\r",bar,rate,label[rate%len],"已經(jīng)下載了",tatol*rate/100,"MB");
27 fflush(stdout);
28 int count=internetspeep*100/tatol;
29 while(count--)//每次進(jìn)度條增加幾條字符,按照下載速度占總大小的百分比老算
30 {
31 bar[rate++]=STYLE;
32 }
33 }
我們來看運(yùn)行結(jié)果:
這樣已經(jīng)很符合我們平時(shí)下載的進(jìn)度條了,但是我還想再優(yōu)化一下時(shí)進(jìn)度條好看一些---------->這樣的形式
代碼優(yōu)化:
顏色優(yōu)化:(https://blog.csdn.net/wuquan_1230/article/details/106077560)參考這篇博客
代碼:
這就實(shí)現(xiàn)了一個(gè)非常好看的進(jìn)度條文章來源:http://www.zghlxwxcb.cn/news/detail-520065.html
三、總結(jié)
今天大家實(shí)現(xiàn)了Linux上的第一個(gè)小程序,進(jìn)度條,希望大家下來可以自己去實(shí)現(xiàn)一下,還是比較好玩的,也可以修改成自己風(fēng)格的進(jìn)度條,我們今天的知識(shí)就講解到這里了,下篇再見文章來源地址http://www.zghlxwxcb.cn/news/detail-520065.html
到了這里,關(guān)于【Linux】-第一個(gè)小程序(進(jìn)度條)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!