0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

教你在Linux上寫一個(gè)進(jìn)度條小程序

dyquk4xk2p3d ? 來(lái)源:入門小站 ? 2023-01-29 11:37 ? 次閱讀

一、前言

Linux 上寫下一個(gè)簡(jiǎn)易的進(jìn)度條小程序。

成品展示

93c0b498-96c4-11ed-bfe3-dac502259ad0.gif

今天的內(nèi)容比較輕松,只需要了解兩個(gè)知識(shí)點(diǎn),這個(gè)小程序就很容易寫出來(lái)了,讓我們開(kāi)始今天的學(xué)習(xí)。

二、理解 ‘ ’ 與 ‘ ’

C 語(yǔ)言中有很多字符,而字符大體分為兩類:可顯字符、控制字符。

控制字符不可顯示,例如 和 就是控制字符。

而在我們平時(shí)打字時(shí),一行寫滿了需要換行,但是新起一行有很多種,例如:

93cdda7e-96c4-11ed-bfe3-dac502259ad0.png

這樣雖然新起一行了,但是不是我們想要的結(jié)果。

我們通常新起一行是在第二行的最左端,但是對(duì)于這個(gè)結(jié)果其實(shí)有兩個(gè)操作:

1.跳轉(zhuǎn)到第二行

2.回到第二行的最左端

有了這個(gè)基本概念,再來(lái)談 和 的作用:

:回車 - 回到文本行的開(kāi)頭

:換行 - 新起一行

所以,其實(shí)我們平時(shí)泛指的換行實(shí)際上是 回車 + 換行

且在語(yǔ)言范疇下,例如 C 語(yǔ)言,換行就可以達(dá)到回車 + 換行的效果。在平常,這一操作還是兩個(gè)步驟。

三、行緩沖

行緩沖這個(gè)概念認(rèn)識(shí)。

1、提出問(wèn)題

首先先了解一下兩個(gè)庫(kù)函數(shù):

sleep:Linux 下的休眠函數(shù),單位是秒。頭文件為#include

fflush:刷新緩沖區(qū)

代碼 1:

#include
intmain()
{
printf("helloxxx");
sleep(3);
return0;
}

現(xiàn)象:

93e6f360-96c4-11ed-bfe3-dac502259ad0.gif

分析:

光標(biāo)停留在文本行的開(kāi)頭,但是字符串沒(méi)有被打印。

反而像是 sleep 函數(shù)先起作用,然后 printf 函數(shù)再?gòu)墓鈽?biāo)處開(kāi)始打印。

打印完之后,shell 提示符緊跟著字符串后顯示。

代碼 2:

#include
intmain()
{
printf("helloxxx
");
sleep(3);
return0;
}

現(xiàn)象:

93f45a50-96c4-11ed-bfe3-dac502259ad0.gif

分析:

printf 打印的字符串先顯示在終端上,光標(biāo)位于字符串的下一行。

sleep 函數(shù)使程序休眠 3 秒后,shell 提示符從光標(biāo)位置開(kāi)始顯示。

代碼 3:

#include
intmain()
{
printf("helloxxx
");
sleep(3);
return0;
}

現(xiàn)象:

93fc5f3e-96c4-11ed-bfe3-dac502259ad0.gif

分析:

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è)保留的空間被稱為緩沖區(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)象:

94037e36-96c4-11ed-bfe3-dac502259ad0.gif

觀察現(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í)間。

由此,我們可以很輕松寫出代碼,例如寫一個(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;
}
94115808-96c4-11ed-bfe3-dac502259ad0.gif

四、進(jìn)度條

好了,接下來(lái)進(jìn)入正題,我們開(kāi)始寫進(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)備

由于采用多文件,所以依賴關(guān)系可以寫成依賴文件列表的樣式:

941a4648-96c4-11ed-bfe3-dac502259ad0.png

分塊邏輯

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è)寫出代碼:

942199a2-96c4-11ed-bfe3-dac502259ad0.png942b83a4-96c4-11ed-bfe3-dac502259ad0.gif

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

#include

externvoidprocess();

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)度條展示

93c0b498-96c4-11ed-bfe3-dac502259ad0.gif

審核編輯:湯梓紅
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • Linux
    +關(guān)注

    關(guān)注

    87

    文章

    11171

    瀏覽量

    208480
  • C語(yǔ)言
    +關(guān)注

    關(guān)注

    180

    文章

    7581

    瀏覽量

    135590
  • 字符
    +關(guān)注

    關(guān)注

    0

    文章

    230

    瀏覽量

    25144
  • 函數(shù)
    +關(guān)注

    關(guān)注

    3

    文章

    4260

    瀏覽量

    62233
  • 小程序
    +關(guān)注

    關(guān)注

    1

    文章

    233

    瀏覽量

    12066

原文標(biāo)題:教你在 Linux 上寫一個(gè)進(jìn)度條小程序

文章出處:【微信號(hào):良許Linux,微信公眾號(hào):良許Linux】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    關(guān)于進(jìn)度條

    我用的labview8.6,初學(xué)者,在那能找到進(jìn)度條??!
    發(fā)表于 10-28 11:35

    如何在程序中加個(gè)進(jìn)度條顯示程序運(yùn)行的進(jìn)度

    由于數(shù)據(jù)很大,程序運(yùn)行的時(shí)間很長(zhǎng),想在程序中加個(gè)進(jìn)度條顯示程序運(yùn)行的
    發(fā)表于 08-14 22:30

    如何為個(gè)運(yùn)行得很慢的程序添加進(jìn)度條或者任何提示?

    問(wèn)題是:該程序的循環(huán)底層VI中,該VI用戶不可更改。較頂層的程序均不存在循環(huán)。為了排解等待程序運(yùn)行過(guò)程中的無(wú)聊,想加個(gè)進(jìn)度條,或者任何會(huì)動(dòng)
    發(fā)表于 09-26 16:59

    請(qǐng)問(wèn)怎么用進(jìn)度條顯示程序進(jìn)度

    怎么用進(jìn)度條顯示程序進(jìn)度
    發(fā)表于 12-24 10:02

    如何顯示個(gè)vi程序運(yùn)行的進(jìn)度條

    程序調(diào)用mtalab腳本節(jié)點(diǎn),運(yùn)行很慢,想設(shè)計(jì)個(gè)進(jìn)度條,實(shí)時(shí)顯示運(yùn)行進(jìn)度,求各位大神幫忙
    發(fā)表于 04-01 13:53

    labview的進(jìn)度條

    這是個(gè)labview的進(jìn)度條程序,比較好用
    發(fā)表于 08-04 14:30

    labview進(jìn)度條

    我用labview2017做了個(gè)文件解壓和復(fù)制的vi,解壓過(guò)程中不知道真實(shí)的解壓進(jìn)度,怎么才能做一個(gè)真實(shí)的進(jìn)度條,要真是的,不是自己規(guī)定的
    發(fā)表于 04-26 09:10

    為什么燒不了程序,進(jìn)度條直不動(dòng)?

    怎么燒不了程序...進(jìn)度條直不動(dòng)啊...
    發(fā)表于 07-18 05:45

    怎么設(shè)置進(jìn)度條

    RT!比如 我創(chuàng)建個(gè)隨意長(zhǎng)度的進(jìn)度條然后我知道個(gè)文件的大小 當(dāng)把這個(gè)文件里的數(shù)據(jù)讀完后進(jìn)度條
    發(fā)表于 08-22 04:35

    如果更新太快,進(jìn)度條對(duì)象無(wú)法正確呈現(xiàn)?

    嗨,所有,我正在更新個(gè)和諧進(jìn)度條對(duì)象的基礎(chǔ)定時(shí)器值。如果我使用的時(shí)間小于1500毫秒,進(jìn)度條對(duì)象背景和邊框不能正確渲染。這段視頻更清楚地
    發(fā)表于 09-20 06:18

    HarmonyOS實(shí)戰(zhàn)——ProgressBar進(jìn)度條組件基本使用

    ProgressBar案例——點(diǎn)擊進(jìn)度條增加實(shí)際進(jìn)度值需求分析:每單擊進(jìn)度條組件時(shí),進(jìn)度條就加 5% 的
    發(fā)表于 09-22 23:31

    Linux下實(shí)現(xiàn)進(jìn)度條程序,通過(guò)makefile進(jìn)行編譯

    1. Linux下實(shí)現(xiàn)進(jìn)度條程序。 通過(guò)makefile進(jìn)行編譯。 建議自主完成個(gè)彩色的
    發(fā)表于 03-12 16:31 ?2042次閱讀

    Linux基礎(chǔ)教程之linux wget下載進(jìn)度條變成多行顯示如何解決

    之前為了 解決Putty客戶端連接到CentOS之后顯示亂碼 的問(wèn)題,設(shè)置了 LANG=zh_CN.UTF-8 之后,使用wget下載的時(shí)候,wget下載進(jìn)度條異常,竟然不能在
    發(fā)表于 10-31 17:04 ?19次下載

    如何利用ChatGPT快速實(shí)現(xiàn)個(gè)控制臺(tái)進(jìn)度條小工具?

    控制臺(tái)程序執(zhí)行些耗時(shí)任務(wù)時(shí),需要向用戶顯示當(dāng)前任務(wù)執(zhí)行的進(jìn)度,以提供清晰的感知。比如個(gè)下載程序
    的頭像 發(fā)表于 01-18 13:41 ?820次閱讀
    如何利用ChatGPT快速實(shí)現(xiàn)<b class='flag-5'>一</b><b class='flag-5'>個(gè)</b>控制臺(tái)<b class='flag-5'>進(jìn)度條</b>小工具?

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

    AWTK是基于C語(yǔ)言開(kāi)發(fā)的跨平臺(tái)GUI框架?!禔WTK使用經(jīng)驗(yàn)》系列文章將介紹開(kāi)發(fā)AWTK過(guò)程中些常見(jiàn)問(wèn)題與解決方案,例如:如何加載外部資源?如何設(shè)計(jì)自定義進(jìn)度條?這些都會(huì)在系列文章進(jìn)行解答
    的頭像 發(fā)表于 04-18 08:25 ?379次閱讀
    【AWTK使用經(jīng)驗(yàn)】如何設(shè)計(jì)立體電池<b class='flag-5'>進(jìn)度條</b>?