Linux用C语言实现进度条
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <string.h>
void drawper(int iFirst, int iSecnd, char* spOut)
{
static int iCrlmm = 0;
int iPer = iFirst*100/iSecnd;
if(iFirst==iSecnd)
sprintf(spOut, "[ %d%]\n", iPer);
else if( iCrlmm == 0)
sprintf(spOut, "[| %d%]\r", iPer);
else if( iCrlmm == 1)
sprintf(spOut, "[/ %d%]\r", iPer);
else if( iCrlmm == 2)
sprintf(spOut, "[- %d%]\r", iPer);
else if( iCrlmm == 3)
sprintf(spOut, "[\\ %d%]\r", iPer);
if(iCrlmm==3)
iCrlmm=0;
else
iCrlmm++;
}
void proessview()
{
char szStr[255] = "=====================================================================";
int iStrLen = strlen(szStr);
char cTmp = '>';
char szOut[10] = "";
int i = 0;
for( i= 0; i<=iStrLen; i++)
{
memset( szOut, 0, sizeof(szOut) );
szStr[i] = cTmp;
drawper(i, iStrLen, szOut);
memcpy(szStr+iStrLen, szOut, strlen(szOut) );
fseek(stdout, 0, SEEK_SET);
fprintf(stdout, szStr);
fflush(stdout);
usleep(300000);
}
}
int main()
{
proessview();
return 1;
}
我在Linux字符终端上实现了两种有趣的彩色进度条。
一种是采取渐进打印的动画效果,另一种是循环打印。
用C语言和shell脚本实现了这两种方式,我不怎么
擅长shell脚本,所以代码写得比较凌乱。两个程序
没事儿的时候可以拿来解闷。
具体的实现方式可以看后面的代码。
测试环境:
OS: fedora 11
gcc: Red Hat 4.4.0-4
shell: bash 4.0.16
C语言程序编译:
gcc -std=gnu99 -g -W -Wall -Wextra -o mytest main.c
执行:
渐进效果:
./mytest
./mytest.sh
随便加个选项,就变成循环效果:
./mytest a
./mytest.sh a
main.c:
================================================================
// 2011年 11月 15日 星期二 11:44:52 CST
// author: 李小丹(Li Shao Dan) 字 殊恒(shuheng)
// K.I.S.S
// S.P.O.T
#include <stdio.h>
#include <assert.h>
#include <unistd.h>
#define BAKBLK "\e[40m" // Black - Background
#define BAKRED "\e[41m" // Red
#define BAKGRN "\e[42m" // Green
#define BAKYLW "\e[43m" // Yellow
#define BAKBLU "\e[44m" // Blue
#define BAKPUR "\e[45m" // Purple
#define BAKCYN "\e[46m" // Cyan
#define BAKWHT "\e[47m" // White
#define CLRRST "\e[0m"
#define COLOR_NUM 8
#define DELAY_TIME 500000
static const char *color_blocks[] = {
BAKRED" "CLRRST,
BAKGRN" "CLRRST,
BAKYLW" "CLRRST,
BAKBLK" "CLRRST,
BAKBLU" "CLRRST,
BAKPUR" "CLRRST,
BAKCYN" "CLRRST,
BAKWHT" "CLRRST
};
static void reset_line();
static unsigned int circle_print_line(unsigned int);
static unsigned int sque_print_line(unsigned int);
int main(int argc, char *argv[])
{
unsigned int b = 0;
unsigned int (*print_progress)(unsigned int);
if(argc != 1)
print_progress = circle_print_line;
else
print_progress = sque_print_line;
for(;;) {
reset_line();
b = print_progress(b);
usleep(DELAY_TIME);
}
return 0;
}
static void reset_line()
{
printf("\r \r");
}
static unsigned int circle_print_line(unsigned int b)
{
assert(b < COLOR_NUM);
//printf("\r");
unsigned int i = b;
do {
printf(color_blocks[i]);
fflush(stdout);
i = (i + 1) % COLOR_NUM;
} while(i != b);
return (b - 1) % COLOR_NUM;
}
static unsigned int sque_print_line(unsigned int c)
{
assert(c < COLOR_NUM);
for(unsigned int i = COLOR_NUM - c - 1; i < COLOR_NUM; ++i) {
printf(color_blocks[i]);
fflush(stdout);
}
return (c + 1) % COLOR_NUM;
}
=====================================================================
mytest.sh:
=====================================================================
#!/bin/bash -
# 2011年 11月 15日 星期二 12:17:21 CST
# author: 李小丹(Li Shao Dan) 字 殊恒(shuheng)
# K.I.S.S
# S.P.O.T
#set -x
BAKBLK="echo -en \\e[40m \\e[0m"
BAKRED="echo -en \\e[41m \\e[0m"
BAKGRN="echo -en \\e[42m \\e[0m"
BAKYLW="echo -en \\e[43m \\e[0m"
BAKBLU="echo -en \\e[44m \\e[0m"
BAKPUR="echo -en \\e[45m \\e[0m"
BAKCYN="echo -en \\e[46m \\e[0m"
BAKWHT="echo -en \\e[47m \\e[0m"
COLOR_NUM=8
DELAY_TIME=0.5
reset_line()
{
echo -en "\\r \\r"
}
sque_print_blocks()
{
j=0
$BAKGRN
$BAKGRN
$BAKGRN
j=$((j+1))
if [ $j -gt $1 ]
then
sleep $DELAY_TIME
return
fi
$BAKRED
$BAKRED
$BAKRED
j=$((j+1))
if [ $j -gt $1 ]
then
sleep $DELAY_TIME
return
fi
$BAKBLK
$BAKBLK
$BAKBLK
j=$((j+1))
if [ $j -gt $1 ]
then
sleep $DELAY_TIME
return
fi
$BAKYLW
$BAKYLW
$BAKYLW
j=$((j+1))
if [ $j -gt $1 ]
then
sleep $DELAY_TIME
return
fi
$BAKBLU
$BAKBLU
$BAKBLU
j=$((j+1))
if [ $j -gt $1 ]
then
sleep $DELAY_TIME
return
fi
$BAKPUR
$BAKPUR
$BAKPUR
j=$((j+1))
if [ $j -gt $1 ]
then
sleep $DELAY_TIME
return
fi
$BAKCYN
$BAKCYN
$BAKCYN
j=$((j+1))
if [ $j -gt $1 ]
then
sleep $DELAY_TIME
return
fi
$BAKWHT
$BAKWHT
$BAKWHT
j=$((j+1))
if [ $j -gt $1 ]
then
sleep $DELAY_TIME
return
fi
}
circle_print_blocks()
{
i="$1"
j=0
while [ true ]
do
if [ "$i" -le "0" ]
then
$BAKGRN
$BAKGRN
$BAKGRN
j=$((j+1))
i=$(((i+1) % COLOR_NUM))
fi
if [ $j -gt "7" ]
then
sleep $DELAY_TIME
return
fi
if [ "$i" -le "1" ]
then
$BAKRED
$BAKRED
$BAKRED
j=$((j+1))
i=$(((i+1) % COLOR_NUM))
fi
if [ $j -gt "7" ]
then
sleep $DELAY_TIME
return
fi
if [ "$i" -le "2" ]
then
$BAKBLK
$BAKBLK
$BAKBLK
j=$((j+1))
i=$(((i+1) % COLOR_NUM))
fi
if [ $j -gt "7" ]
then
sleep $DELAY_TIME
return
fi
if [ "$i" -le "3" ]
then
$BAKYLW
$BAKYLW
$BAKYLW
j=$((j+1))
i=$(((i+1) % COLOR_NUM))
fi
if [ $j -gt "7" ]
then
sleep $DELAY_TIME
return
fi
if [ "$i" -le "4" ]
then
$BAKBLU
$BAKBLU
$BAKBLU
j=$((j+1))
i=$(((i+1) % COLOR_NUM))
fi
if [ $j -gt "7" ]
then
sleep $DELAY_TIME
return
fi
if [ "$i" -le "5" ]
then
$BAKPUR
$BAKPUR
$BAKPUR
j=$((j+1))
i=$(((i+1) % COLOR_NUM))
fi
if [ $j -gt "7" ]
then
sleep $DELAY_TIME
return
fi
if [ "$i" -le "6" ]
then
$BAKCYN
$BAKCYN
$BAKCYN
j=$((j+1))
i=$(((i+1) % COLOR_NUM))
fi
if [ $j -gt "7" ]
then
sleep $DELAY_TIME
return
fi
if [ "$i" -le "7" ]
then
$BAKWHT
$BAKWHT
$BAKWHT
j=$((j+1))
i=$(((i+1) % COLOR_NUM))
fi
if [ $j -gt "7" ]
then
sleep $DELAY_TIME
return
fi
done
}
i=0
while [ true ]
do
if [ -z "$1" ]
then
sque_print_blocks $i
else
circle_print_blocks $i
fi
i=$(((i+1) % COLOR_NUM))
reset_line
done
很想实现在linux控制台上打印进度条,这样对于运行时间长的程序就不至于让用户等的不耐烦了。
众所周知,ncurse库能很方便的在控制台上输出一些很花样信息,当然包括进度条这样小case的东西啦。但是,唯一然人不能接受的是,为了让控制台上及时的显示输出字符,必须用flush之类的函数刷新缓冲区,这样就导致要清除当前屏幕。如果,屏幕上有一些信息很重要的话,清除屏幕是非常让你难以理解的。另外termcap库也能实现这些功能,但是tgoto,tputs这样的函数直到现在我也不会用。
天无绝人之路,根据rpm的进度条显示代码,我编写了以下的程序,可以方便的实现进度条的打印。当然你也可以随便在自己的程序中加上这些代码(只要你愿意哈)。
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#define LEN 40
#define TIM 50000000
#define done '+'
#define none '-'
#define del() putchar('\b')
#define motion() \
{ \
putchar(done);fflush(stdout);delay();\
del(); \
putchar('x');fflush(stdout);delay();\
del(); \
putchar('|'); fflush(stdout);delay();\
del(); \
putchar('/'); fflush(stdout);delay();\
del(); \
putchar(done); \
}
intmode =-1;
voiddelay()
{
inti;
for(i=0;i<TIM;i++);
}
voidloop(inti, intj) {
//print progress bar.
for(j=0;j<i-1;j++)
putchar(done);
motion();
//print space after progress bar.
for(j=1;j<LEN-i;j++)
putchar(none);
}
voiddomino(inti, intj)
{
for(j=0;j<i-1;j++)
putchar('_');
putchar('/');fflush(stdout);
delay();del();
putchar('_');fflush(stdout);
delay();
for(j=1;j<LEN-i;j++)
putchar('|');
}
voidsharp(inti, intj)
{
for(j=0;j<i;j++)
putchar('#');
for(j=1;j<LEN-i;j++)
putchar(' ');
}
voidadd(inti, intj)
{
for(j=0;j<i;j++)
putchar('+');
for(j=1;j<LEN-i;j++)
putchar('-');
}
voidprogress()
{
inti,j,k;
for(i=1;i<LEN;i++){
if(i != 1){
//delete all character of current line.
for(k=0;k<LEN+6;k++)
putchar('\b');
}
switch(mode){
case0:
loop(i,j);break;
case1:
domino(i,j);break;
case2:
sharp(i,j);break;
case3:
default:
add(i,j);break;
}
//finally, print percent.
fprintf(stdout," %3d%%",i*100/(LEN-1));
fflush(stdout);//output message on time, please.
//delay();
sleep(1);
}
}
intmain(intargc,char*argv[])
{
intc;
if(argc< 2)
return1;
while((c=getopt(argc,argv,"ldsa"))!= EOF) {
switch(c){
case'l':
mode= 0;break;
case'd':
mode= 1;break;
case's':
mode= 2;break;
case'a':
mode= 3;break;
default:
return1;
}
}
progress();
return0;
}