文章目錄
- 預備知識
- 一、理解回車換行
- 二、認識行緩沖
- 1、代碼一、二(回車換行理解)
- 2、代碼三、四(sleep函數和ffush函數理解)
- 三、簡單倒計時
- 1. 倒計時代碼
- 2、效果展示
- 四、進度條
- 1、效果展示
- 2、進度條代碼
- makefile
- ProcessBar.h
- ProcessBar.c
- main.c
- 3、實現過程分析
- 4.3.1 進度條實現樣式
- 4.3.2 進度條實現方法
預備知識
一、理解回車換行
- 在我們熟悉的C語言中,換行就可以跳轉的下一行開頭 ,但其實這一操作有兩個步驟,\r (回車)和 \n(換行)
- 也就是先回到開頭,再進行換行
\r 回車就是回到這一行開頭
\n 換行就是另起一行
二、認識行緩沖
- 在內存中預留了一塊空間,用來緩沖輸入或輸出的數據,這個保留的空間被稱為緩沖區。
- 下面我們通過幾個代碼來理解一下:
1、代碼一、二(回車換行理解)
代碼一:
#include<stdio.h>int main()
{printf("hello world\n");return 0;
}
代碼二:
- 那我將這個
\n
換成了\r
,再次打印會出現什么情況?
#include<stdio.h>int main()
{printf("hello world\r");return 0;
}
- 發現 \n 可以打印出來,而 \r,不能打印出來,因為顯示器模式是行刷新緩沖區是按行緩沖的,沒有\n,就不能立即刷新。 \r 回到行首后,會進行覆蓋寫,shell 提示符會覆蓋掉之前寫的 “hello world”,如果我們在 “hello world” 不加 \r,則不會進行覆蓋寫,shell 提示符會順著 “hello world” 往后寫
如下:
2、代碼三、四(sleep函數和ffush函數理解)
- 行緩沖是緩沖區刷新策略的一種,在行緩沖模式下,當輸入和輸出中遇到 ‘\n’ 換行時,就會刷新緩沖區,下面我們認識頭文件<unistd.h>的三個函數
sleep:Linux 下的休眠函數,單位是秒
usleep:和sleep 一樣,單位ms(即10-6 m)
fflush :刷新緩沖區
代碼 3:
#include<stdio.h>
#include<unistd.h>int main()
{printf("hello world");sleep(3);return 0;
}
- 我們寫的這個C語言程序是從上到下依次執行的,而我們看到的是先休眠后打印
- 這是因為數據保存在緩沖區中,沒有主動刷新。當程序退出后,保存在緩沖區中的數據被自動刷新出來了,如果我們想提前刷新,便可以調用
fflush
函數來刷新緩沖區
代碼四:
#include <stdio.h>
#include <unistd.h>
int main()
{printf("hello world");fflush(stdout);printf("\n");sleep(3);return 0;
}
- 這次 “hello world” 被直接打印出來,我們加 \n避免shell 提示符出現在 “hello world” 后面
三、簡單倒計時
1. 倒計時代碼
#include <stdio.h>
#include <unistd.h>
int main()
{int cnt=10;while(cnt>=0){printf("%-2d\r",cnt);fflush(stdout);sleep(1);cnt--; }printf("\n");return 0;
}
2、效果展示
具備了以上介紹的知識,接下來我們就實現進度條了
四、進度條
1、效果展示
2、進度條代碼
makefile
processbar:ProcessBar.c main.cgcc -o $@ $^
.PHONY:clean
clean: rm -rf processbar
ProcessBar.h
#pragma once
#include <string.h>
#include <unistd.h>
#include <stdio.h>// 進度條箭頭
#define TAIL '>'// 進度條的數組大小
#define Length 102// 進度條加載的進度條
#define Style '='// 重定義函數指針
typedef void (*callback_t)(double, double);// 進度條的實現
void ProcBar(double total, double current);
ProcessBar.c
#include "ProcessBar.h"#define LIGHT_CYAN "\033[1;36m" // 亮青色
#define NONE "\033[m" //截斷// 顯示進度
const char* lable = "|/-\\";void ProcBar(double total, double current)
{char bar[Length];// 初始化進度條memset(bar, '\0', sizeof(bar));int len = strlen(lable);int cnt = 0;double rate = (current * 100.0) / total;// 循環次數int loop_count = (int)rate;while (cnt < loop_count){bar[cnt++] = Style;if (rate < 100)bar[loop_count] = TAIL;}// 打印顯示printf(LIGHT_CYAN"[%-100s]"NONE"[%.2lf%%][%c]\r", bar, rate, lable[cnt % len]);// 刷新緩沖區fflush(stdout);
}
main.c
#include "ProcessBar.h"// 網絡帶寬【1mb】
double bandwidth = 1024 * 1024 * 1.0;void download(double filesize, callback_t cb)
{// 累計下載的數據量double current = 0.0;printf("download begin, current: %lf\n", current);while (current <= filesize){// 使用函數指針更新界面cb(filesize, current);//從網絡中獲取數據//......// 睡眠usleep(100000);// 累計下載current += bandwidth;}printf("\ndownload done, filesize: %lf\n", filesize);
}int main()
{// 測試調用//download(100 * 1024 * 1024, ProcBar);download(2 * 1024 * 1024, ProcBar);//download(200*1024*1024,ProcBar);//download(400*1024*1024,ProcBar);download(50*1024*1024,ProcBar);download(10*1024*1024,ProcBar);// 測試//ProcBar(100.0, 56.9);//ProcBar(100.0, 1.0);//ProcBar(100.0, 99.9);//ProcBar(100.0, 100);return 0;
}
3、實現過程分析
4.3.1 進度條實現樣式
進度條樣式 :
- 進度條的主要內容是兩個中括號包裹,中間進度顯示以=>的方式進行推進呈現
進度條百分比:
- 顯示當前進度百分比,隨著進度不斷推進,百分比也在增加
進度條旋轉字符:
- 顯示加載樣式,可以利用一個旋轉的字符,例如 [] 的樣式,順時針不斷旋轉,依次為 “| / - \”,注意 ** 也是轉義字符,因此需要兩個 *\ *
進度條顏色:
c語言顏色參考
我們可以根據自己的喜好給進度條上色,在此我們找到顏色參照表
4.3.2 進度條實現方法
-
預留進度條大小為 100 個 = ,外加 1 個 > ,加上保存 \0 的位置,定義一個102個單位的長度的
bar
數組。 -
如果將打印放在循環中的話,在打印的時候會變得卡卡的,我們可以將打印放到循環外面,等數組放上
=>
后,在一起打印,這樣更好 -
我們又實現了一個函數
download()
,把ProcBar()
,作為參數傳遞給download()
,用usleep函數模擬下載時間,然后循環起來回調processbar()函數,便實現了進度條 -
最后考慮到第二次下載,bar數組滿了,我們再每次調用download()函數時,清空bar數組,完成實現~~
-
這就實現了我們最終的效果
最后本文就到這里結束了,感謝大家的收看,請多多指點~