一、前言
在 Linux 上寫(xiě)下一個(gè)簡(jiǎn)易的進(jìn)度條小程序。
成品展示:
今天的內(nèi)容比較輕松,只需要了解兩個(gè)知識(shí)點(diǎn),這個(gè)小程序就很容易寫(xiě)出來(lái)了,讓我們開(kāi)始今天的學(xué)習(xí)。
二、理解 ‘ ’ 與 ‘ ’
C 語(yǔ)言中有很多字符,而字符大體分為兩類(lèi):可顯字符、控制字符。
控制字符不可顯示,例如 和 就是控制字符。
而在我們平時(shí)打字時(shí),一行寫(xiě)滿(mǎn)了需要換行,但是新起一行有很多種,例如:
這樣雖然新起一行了,但是不是我們想要的結(jié)果。
我們通常新起一行是在第二行的最左端,但是對(duì)于這個(gè)結(jié)果其實(shí)有兩個(gè)操作:
1.跳轉(zhuǎn)到第二行
2.回到第二行的最左端
有了這個(gè)基本概念,再來(lái)談 和 的作用:
:回車(chē) - 回到文本行的開(kāi)頭
:換行 - 新起一行
所以,其實(shí)我們平時(shí)泛指的換行實(shí)際上是 回車(chē) + 換行。
且在語(yǔ)言范疇下,例如 C 語(yǔ)言,換行就可以達(dá)到回車(chē) + 換行的效果。在平常,這一操作還是兩個(gè)步驟。
三、行緩沖
行緩沖這個(gè)概念認(rèn)識(shí)。
1、提出問(wèn)題
首先先了解一下兩個(gè)庫(kù)函數(shù):
sleep:Linux 下的休眠函數(shù),單位是秒。頭文件為#include
fflush:刷新緩沖區(qū)
代碼 1:
#includeintmain() { printf("helloxxx"); sleep(3); return0; }
現(xiàn)象:
分析:
光標(biāo)停留在文本行的開(kāi)頭,但是字符串沒(méi)有被打印。
反而像是 sleep 函數(shù)先起作用,然后 printf 函數(shù)再?gòu)墓鈽?biāo)處開(kāi)始打印。
打印完之后,shell 提示符緊跟著字符串后顯示。
代碼 2:
#includeintmain() { printf("helloxxx "); sleep(3); return0; }
現(xiàn)象:
分析:
printf 打印的字符串先顯示在終端上,光標(biāo)位于字符串的下一行。
sleep 函數(shù)使程序休眠 3 秒后,shell 提示符從光標(biāo)位置開(kāi)始顯示。
代碼 3:
#includeintmain() { printf("helloxxx "); sleep(3); return0; }
現(xiàn)象:
分析:
printf 打印的字符串沒(méi)有顯示到終端,光標(biāo)一直停留在該打印字符串的一行
sleep 函數(shù)休眠三秒后,shell 提示符直接打印在了屏幕上。并沒(méi)有看到字符串。
觀察上面的現(xiàn)象,我們提出幾個(gè)問(wèn)題:
代碼 1 好像是先執(zhí)行了 sleep ,在執(zhí)行 printf ,是這樣嗎?
代碼 2 加上了 ‘ ’ ,字符串一開(kāi)始就顯示了,為什么?
代碼 3 好像什么都沒(méi)打印,這是為什么?
在解答這些問(wèn)題之后,我們先了解一下行緩沖。
2、認(rèn)識(shí)行緩沖
在內(nèi)存中預(yù)留了一塊空間,用來(lái)緩沖輸入或輸出的數(shù)據(jù),這個(gè)保留的空間被稱(chēng)為緩沖區(qū)。
我們之前或多或少都聽(tīng)說(shuō)過(guò)緩沖區(qū)。
在代碼 1 中,由于程序是按照數(shù)據(jù)執(zhí)行的,所以必定是先執(zhí)行 printf 。
但是數(shù)據(jù)沒(méi)有顯示,所以這時(shí)候,數(shù)據(jù)就一定被保存在某個(gè)位置,保存的位置就是緩沖區(qū)。
而要讓數(shù)據(jù)顯示,是需要刷新緩沖區(qū)的。
行緩沖是緩沖區(qū)刷新策略的一種,在行緩沖模式下,當(dāng)輸入和輸出中遇到 ‘ ’ 換行時(shí),就會(huì)刷新緩沖區(qū)。
有了這個(gè)概念,我們繼續(xù)分析問(wèn)題。
3、解答與拓展
解答:
問(wèn)題 1:代碼 1 好像是先執(zhí)行了 sleep ,在執(zhí)行 printf ,是這樣嗎?
當(dāng)然不是。由于程序是按照順序執(zhí)行的,所以必定是先執(zhí)行完 printf 在執(zhí)行 sleep 。
而數(shù)據(jù)沒(méi)有被顯示出來(lái)的原因是:數(shù)據(jù)保存在緩沖區(qū)中,但是沒(méi)有主動(dòng)刷新,當(dāng)程序退出后,保存在緩沖區(qū)中的數(shù)據(jù)被自動(dòng)刷新出來(lái)了。
所以才會(huì)造成這種現(xiàn)象。
問(wèn)題 2:代碼 2 加上了 ,字符串一開(kāi)始就顯示了,為什么?
這里由于是直接往顯示器上打印,所以采用的刷新方式為行緩沖。
所以執(zhí)行碰到 ‘ ’ 時(shí),就會(huì)把在緩沖區(qū)中的 (換行符之前) 的內(nèi)容全部刷新出來(lái)。
所以這段代碼一開(kāi)始就會(huì)有數(shù)據(jù)顯示,然后再 sleep 休眠。
問(wèn)題 3:代碼 3 好像什么都沒(méi)打印,這是為什么?
之前說(shuō)過(guò) 是換行,所以當(dāng) printf 遇到 時(shí),就把光標(biāo)移到開(kāi)頭。sleep 睡眠后,當(dāng)程序退出,shell 打印提示符時(shí),就覆蓋了字符串。
拓展:
數(shù)據(jù)真的是臨時(shí)保留在緩沖區(qū)里的嗎?光標(biāo)如何理解?
我們用一段代碼來(lái)理解這兩個(gè)問(wèn)題:
#include#include intmain() { printf("helloxxx "); fflush(stdout); sleep(3); return0; }
現(xiàn)象:
觀察現(xiàn)象,我們發(fā)現(xiàn)當(dāng)我們使用fflush主動(dòng)刷新緩沖區(qū)后,數(shù)據(jù)就顯示在了屏幕上;且因?yàn)?‘ ’ 的原因,光標(biāo)指向字符串開(kāi)頭;當(dāng)打印 shell 提示符時(shí),就直接從光標(biāo)位置開(kāi)始覆蓋。
所以對(duì)于這兩個(gè)問(wèn)題,我們已經(jīng)得到了答案:
1.數(shù)據(jù)被臨時(shí)保存在于緩沖區(qū)中,通過(guò)刷新就可以顯示
2.數(shù)據(jù)是從光標(biāo)位置開(kāi)始打印的。
一句話理解光標(biāo):光標(biāo)和顯示器匹配,光標(biāo)在哪里,顯示器打印的時(shí)候就從哪里開(kāi)始打印。
4、倒計(jì)時(shí)
基于對(duì)上面的理解,我們先實(shí)現(xiàn)一個(gè)簡(jiǎn)單的倒計(jì)時(shí)。
倒計(jì)時(shí)就是在屏幕上不斷顯示數(shù)字,每次在同一位置顯示,并將之前的數(shù)據(jù)覆蓋。
既然是每次要從頭開(kāi)始覆蓋,那么就可以用 ‘ ’ 來(lái)實(shí)現(xiàn)每次回到行首,并且可以通過(guò)相應(yīng)的格式化控制顯示多位打印。
但是 ‘ ’ 不會(huì)主動(dòng)刷新,所以要用fflush函數(shù)主動(dòng)刷新緩沖區(qū)。
在每次刷新之后,使用 sleep 函數(shù),間隔一定的時(shí)間。
由此,我們可以很輕松寫(xiě)出代碼,例如寫(xiě)一個(gè)從 10 開(kāi)始的倒計(jì)時(shí):
#include#include intmain() { inti=10; for(;i>=0;i--){ //位寬控制, 回到開(kāi)頭 printf("%2d ",i); fflush(stdout);//主動(dòng)刷新 sleep(1);//休眠 } printf(" ");//換行,打印提示符 return0; }

四、進(jìn)度條
好了,接下來(lái)進(jìn)入正題,我們開(kāi)始寫(xiě)進(jìn)度條。
進(jìn)度條樣式:
主體樣式為兩個(gè)中括號(hào)包裹,中間=>推進(jìn)的方式呈現(xiàn),比如:[======>]
主體右側(cè)中括號(hào)位置保持不變,中間元素不斷推進(jìn),比如:[=> ]
顯示當(dāng)前加載進(jìn)度,用[num%]顯示,num 隨著進(jìn)度條的不斷推進(jìn)而變化
顯示加載樣式,可以利用一個(gè)旋轉(zhuǎn)的字符,例如[]的樣式,順時(shí)針不斷旋轉(zhuǎn)
大約呈現(xiàn)狀態(tài)為:[========>] [15%] []
采用多文件:
文件存放在proc目錄中
proc.h :函數(shù)聲明
proc.c :進(jìn)度條邏輯
main.c :函數(shù)調(diào)用
makefile準(zhǔn)備:
由于采用多文件,所以依賴(lài)關(guān)系可以寫(xiě)成依賴(lài)文件列表的樣式:
分塊邏輯:
1.進(jìn)度條主體
預(yù)留進(jìn)度條大小為 100 個(gè)=,外加 1 個(gè)>,加上保存'?'的位置,用數(shù)組存儲(chǔ)為 102 個(gè)單位。
進(jìn)度條是一行中的,所以需要用到' ',每次都需要使用fllush主動(dòng)刷新緩沖區(qū)。
每次刷新出數(shù)據(jù)之后,將 = 填充到數(shù)組中,并且顯示 > 。在最后一次顯示時(shí),控制 > 不要顯示。
然后休眠一小會(huì)。由于休眠用 sleep 函數(shù)太慢。所以可以用 usleep 函數(shù)休眠,usleep 函數(shù)的參數(shù)單位是微秒。
根據(jù)這個(gè)寫(xiě)出代碼:
2.百分比顯示
%% 顯示為一個(gè) % ,而 %d 為數(shù)字,這步很簡(jiǎn)單,只要在 printf 語(yǔ)句中加上內(nèi)容:
printf("[%-100s][%d%%] ",bar,i);
3.旋轉(zhuǎn)光標(biāo):
光標(biāo)旋轉(zhuǎn)方向?yàn)轫槙r(shí)針旋轉(zhuǎn),那么旋轉(zhuǎn)時(shí)就可以用數(shù)組保存。
旋轉(zhuǎn)每次顯示內(nèi)容分別為| / - ,\代表一個(gè) ,因?yàn)楹?結(jié)合的會(huì)被解析為轉(zhuǎn)義字符,將其保存到字符串中。
而由于字符串一共就四個(gè)字符,所以輸出的時(shí)候需要控制輸出位置。
代碼:
constchar*str="|/-";//字符串 printf("[%-100s][%d%%][%c] ",bar,i,str[i%4]);//輸出語(yǔ)句
完整代碼:
proc.h:
#pragmaonce #includeexternvoidprocess();
proc.c:
#include"proc.h" #include#include #defineSIZE102//數(shù)組大小 #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;?//?填充數(shù)據(jù) ??????if?(i?!=?100)?{ ??????????bar[i]?=?FLAG;?//?如果不是最后一次則顯示?> } usleep(100000);//休眠 } printf(" "); }
test.c
#include"proc.h" intmain() { process(); return0; }
進(jìn)度條展示:
-
Linux
+關(guān)注
關(guān)注
87文章
11373瀏覽量
211298 -
C語(yǔ)言
+關(guān)注
關(guān)注
180文章
7618瀏覽量
138662 -
字符
+關(guān)注
關(guān)注
0文章
234瀏覽量
25314 -
函數(shù)
+關(guān)注
關(guān)注
3文章
4353瀏覽量
63296 -
小程序
+關(guān)注
關(guān)注
1文章
241瀏覽量
12407
原文標(biāo)題:教你在 Linux 上寫(xiě)一個(gè)進(jìn)度條小程序
文章出處:【微信號(hào):良許Linux,微信公眾號(hào):良許Linux】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
如何在程序中加一個(gè)進(jìn)度條顯示程序運(yùn)行的進(jìn)度
如何為一個(gè)運(yùn)行得很慢的程序添加進(jìn)度條或者任何提示?
如何顯示一個(gè)vi程序運(yùn)行的進(jìn)度條
labview進(jìn)度條
怎么設(shè)置進(jìn)度條?
如果更新太快,進(jìn)度條對(duì)象無(wú)法正確呈現(xiàn)?
HarmonyOS實(shí)戰(zhàn)——ProgressBar進(jìn)度條組件基本使用
在Linux下實(shí)現(xiàn)進(jìn)度條程序,通過(guò)makefile進(jìn)行編譯
Linux基礎(chǔ)教程之linux wget下載進(jìn)度條變成多行顯示如何解決
如何利用ChatGPT快速實(shí)現(xiàn)一個(gè)控制臺(tái)進(jìn)度條小工具?

【AWTK使用經(jīng)驗(yàn)】如何設(shè)計(jì)立體電池進(jìn)度條?

評(píng)論