在網絡中,進度條隨處可見,無論是下載還是上傳,進度條都幫助我們判斷當前的進展情況。然而,今天我們將討論的進度條僅具備外觀。首先,讓我們了解一下回車的概念。
1.1 回車的概念
在計算機出現之前,有一種名為電傳打字機(Teletype Model 33)的機械打字機,每秒鐘可以打10個字符。但在換行時需要0.2秒,這段時間內如果有新字符傳輸過來,字符可能會丟失。為了解決這個問題,研發人員在每行結尾添加了兩個結束字符:一個是“回車”,指示打字機將打印頭定位到左邊界而不卷動滾筒;另一個是“換行”,指示打字機卷動滾筒而不改變水平位置。隨著計算機的發明,這兩個概念被引入計算機中。由于存儲器昂貴,一些科學家認為在每行結尾添加兩個字符太浪費,因此出現了分歧。
回車 的本義是將光標重新回到本行的開頭,英文為return,控制字符為CR(Carriage Return)。換行 的本義是將光標移到下一行(不一定是下一行的行首),英文為newline,控制字符為LF(Line Feed)。
符號 | ASCII碼 | 意義 |
---|---|---|
10 | 換行NL | |
13 | 回車CR |
在進度條中,我們需要使用 來將光標回到一行的開頭。
1.2 緩沖區的概念
緩沖區是內存的一部分,用于暫存輸入或輸出的數據。根據對應的是輸入設備還是輸出設備,緩沖區分為輸入緩沖區和輸出緩沖區。當我們使用printf函數時,內容先進入緩沖區,然后再從緩沖區打印到屏幕。由于代碼中存在sleep,緩沖區的內容不會立即打印到屏幕,這會影響進度條的運行。因此,需要使用fflush強制將緩沖區的內容輸出。輸出緩沖區的流是stdout,將stdout作為fflush函數的參數即可輸出內容。大家可以嘗試以下代碼:
#include <stdio.h> #include <unistd.h> int main(){ printf("hello makefile"); sleep(3); return 0; }
1.3 makefile的準備
為了充分利用linux下的makefile,本次進度條將分為以下三個文件編寫:
progressbar.c progressbar.h test.c
在編寫之前,我們先配置makefile的內容:
progressbar:test.o progressbar.o gcc -o progressbar test.o progressbar.o test.o:test.c gcc -c test.c progressbar.o:progressbar.c gcc -c progressbar.c .PHONY:clean clean: rm -f progressbar progressbar.o test.o
配置完成后,在progressbar.h中編寫本次程序可能用到的頭文件:
#pragma once #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <time.h> #include <string.h> typedef void(*callback_c)(double rate); //函數指針 void progress();//進度條1.0 void progress2(double rate);//進度條2.0
1.4 進度條1.0
旋轉光標的存在是為了模擬現實中進度條卡住的情況,判斷進度條是否還在運行。
char load[4] = {'|','/','-',''};//旋轉光標 void progress(){ char str[101]; memset(str,0,sizeof(str)); int i = 0; for(i = 0;i<100;i++){ str[i] = '#'; printf("[%-100s][%d%%][%c] ",str,i+1,load[i%4]); fflush(stdout); usleep(50000); } printf(" "); }
這個進度條僅具備外觀,沒有實際意義。
1.5 進度條2.0
模擬下載過程,通過當前下載的比例來判斷進度。
char p_str[101]; void progress2(double rate){ int cnt = (int)rate; printf("[%-100s][%.1lf%%][%c] ",p_str,rate,load[cnt%4]); fflush(stdout); p_str[(int)rate] = '#'; } #include "progressbar.h" int filesize = 1024*1024*1024;//假設文件大小為1GB void download(callback_c cb){ //模擬下載過程 srand((unsigned int)time(NULL));//隨機下載文件的大小 int total = filesize;//已下載文件的大小 while(total>0) { usleep(20000); int load = rand()%(1024*1024*10);//下載速度0~1MB*10 total-=load; if(total<0) total = 0; double rate = (double)(filesize-total)/filesize*100; cb(rate); } printf(" "); }