C语言实现进度条

前言

为什么我会整理这部分的学习笔记呢?因为我在学习这部分内容是对缓冲区有了全新的认识(此时我还没有学过操作系统),想趁此记录一下我的学习心得。

一、前置知识

1. 回车换行

  • 概念:回车(\r)是将光标移到行首;换行(\n)是将光标移到下一行。在 C 语言中,\n 是回车换行组合动作。

2. 缓冲区

  • 原理:C 语言程序默认打开标准输入(stdin)、标准输出(stdout,对应显示器)、标准错误(stderr)三个流。printf 输出内容先存入缓冲区,满足以下条件才刷新显示:
    • 遇到换行符(\n)。
    • 缓冲区写满。
    • 程序结束。
    • 使用 fflush 函数强制刷新。
  • 示例代码
    #include <unistd.h>
    #include <stdio.h>
    int main() {
        printf("hello world\n"); // 有换行,先执行 printf 再 sleep
        sleep(2);
        return 0;
    }
    • 无换行时,printf 内容存缓冲区,执行 sleep;若要强制刷新,需添加 fflush(stdout)
      #include <unistd.h>
      #include <stdio.h>
      int main() {
          printf("hello world"); 
          fflush(stdout); // 刷新 stdout 流,立即显示
          sleep(2);
          return 0;
      }

二、实战:命令行倒计时实现 

#include <unistd.h>
#include <stdio.h>
int main() {
    int cnt = 10;
    while (cnt >= 0) {
        printf("%-2d\r", cnt); // \r 使光标回行首,覆盖显示;%-2d 数字居左对齐,占两位
        fflush(stdout); // 无换行时强制刷新缓冲区
        --cnt;
        sleep(1); // 暂停 1 秒
    }
    printf("\n"); // 防止命令行覆盖倒计时显示
    return 0;
}

三、进度条实现

版本一

1. processBar.h

#define NUM 102
#define BODY '='
#define RIGHT '>'
#define TOP 100
extern void processBar(int speed);
  • 定义了进度条相关的常量和函数声明,extern用于告诉编译器processBar函数在其他文件中定义。

2. processBar.c 文件

#include "processBar.h"
#include <stdio.h>
#include <string.h>
#include <unistd.h>

const char* label = "|/-\\";  // 模拟旋转光标

void processBar(int speed) {
    char bar[NUM];
    memset(bar, '\0', sizeof(bar)); // 初始化进度条数组
    int len = strlen(label);
    int cnt = 0;
    while (cnt <= TOP) {
        printf("[%-100s][%d%%] %c\r", bar, cnt, label[cnt % len]);  // 预留100个字符空间,左对齐显示进度条
        fflush(stdout);  // 手动刷新缓冲区
        bar[cnt++] = BODY; // 更新进度条字符
        if (cnt < 100) bar[cnt] = RIGHT; // 处理临界:在进度未达 100% 时,显示进度条头部的>符号。
        usleep(speed);
    }
    printf("\n");
}
  • printf("%-100s%d%%%c\r", bar, cnt, label[cnt % len]);:输出进度条、百分比和旋转光标,\r使光标回到行首,实现覆盖效果。

3. main.c 文件

#include "processBar.h"

int main() {
    processBar(100000);  // 调用进度条函数
    return 0;
}
  • 调用processBar函数启动进度条。

版本二:进度条调用

1. processBar.h

#define NUM 102
#define BODY '='
#define RIGHT '>'
#define TOP 100
extern void processBar(int rate);
extern void initBar();
  • 新增initBar函数声明,用于初始化进度条数组。

2. processBar.c 文件

#include <stdio.h>
#include <string.h>
#include <unistd.h>

char bar[NUM];
const char* label = "|/-\\";

// 用于设置进度条的颜色
#define GREEN "\033[0;32;32m" 
#define NONE "\033[m"

void processBar(int rate) {
    if (rate < 0 || rate > 100) return; // 确保传入的进度值在 0 - 100 之间
    int len = strlen(label);
    printf(GREEN"[%-100s]"NONE"[%d%%] %c\r", bar, rate, label[rate % len]);  // 输出带颜色的进度条
    fflush(stdout);
    bar[rate++] = BODY;
    if (rate < 100) bar[rate] = RIGHT;
    else initBar(); // 当进度达到 100% 时,调用initBar函数初始化进度条数组。
}

void initBar() {
    memset(bar, '\0', sizeof(bar));
}

3. main.c 文件

#include "processBar.h"
#include <unistd.h>

typedef void (*callback_t)(int);  // 定义函数指针类型,用于回调进度条函数

// 模拟下载过程,通过回调函数cb展示下载进度
void downLoad(callback_t cb) {
    int total = 1024, cur = 0;
    while (cur <= total) {
        int rate = cur * 100 / total;  // 计算进度百分比
        cb(rate);  // 通过回调函数展示进度
        usleep(50000);  // 模拟下载耗时
        cur += 10;  // 更新已下载量
    }
    printf("\n");
}


// 在main函数中多次调用downLoad函数,模拟多个下载任务。
int main() {
    printf("downLoad1:");
    downLoad(processBar);
    printf("downLoad2:");
    downLoad(processBar);
    printf("downLoad3:");
    downLoad(processBar);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值