Linux C++ 进度条进阶美化与工程化封装

一、ANSI 转义序列:终端色彩与光标控制

Linux 终端支持 ANSI 转义序列,可以实现文字着色、光标移动、清除行等高级效果,是美化进度条的基础。

1.1 常用颜色码(前景色)
颜色 代码 颜色 代码
黑色 30 红色 31
绿色 32 黄色 33
蓝色 34 紫色 35
青色 36 白色 37
1.2 常用光标 / 清屏控制
  • \033[K:清除光标位置到行尾的内容
  • \033[2K:清除整行内容
  • \033[nA:光标向上移动 n 行
  • \033[nB:光标向下移动 n 行

二、版本 4:彩色动态进度条

加入绿色进度条、百分比高亮、完成后变色提示,视觉效果大幅提升。

cpp 复制代码
#include <iostream>
#include <unistd.h>
#include <string>

const int BAR_LEN = 50;

// ANSI 颜色宏
#define COLOR_GREEN  "\033[32m"
#define COLOR_YELLOW "\033[33m"
#define COLOR_RED    "\033[31m"
#define COLOR_RESET  "\033[0m"

int main() {
    for (int i = 0; i <= 100; ++i) {
        int fill = i * BAR_LEN / 100;

        std::cout << "\r" COLOR_GREEN "[";
        // 填充部分用绿色
        for (int j = 0; j < fill; ++j) {
            std::cout << "=";
        }
        // 箭头用黄色
        if (fill < BAR_LEN) {
            std::cout << COLOR_YELLOW ">";
        }
        // 空白部分重置颜色
        std::cout << COLOR_RESET;
        for (int j = fill + 1; j < BAR_LEN; ++j) {
            std::cout << " ";
        }

        // 百分比数字高亮
        if (i == 100) {
            std::cout << COLOR_GREEN "] " << i << "% 完成" COLOR_RESET;
        } else {
            std::cout << "] " COLOR_YELLOW << i << "%" COLOR_RESET;
        }

        std::cout.flush();
        usleep(40000);
    }
    std::cout << std::endl;
    return 0;
}

三、版本 5:带速度与剩余时间估算的进度条

模拟真实任务场景,加入已处理量 / 总量、处理速度、预计剩余时间(ETA),是工程中最实用的版本。

cpp 复制代码
#include <iostream>
#include <unistd.h>
#include <time.h>
#include <string>

const int BAR_LEN = 40;
#define COLOR_GREEN  "\033[32m"
#define COLOR_YELLOW "\033[33m"
#define COLOR_CYAN   "\033[36m"
#define COLOR_RESET  "\033[0m"

int main() {
    const int total = 200;  // 模拟总任务量
    time_t start_time = time(NULL);

    for (int i = 0; i <= total; ++i) {
        // 计算进度百分比
        double percent = (double)i / total * 100;
        int fill = (int)(percent * BAR_LEN / 100);

        // 计算速度和剩余时间
        time_t now = time(NULL);
        double elapsed = difftime(now, start_time);
        double speed = (elapsed > 0) ? (i / elapsed) : 0;
        int eta = (speed > 0) ? (int)((total - i) / speed) : 0;

        // 输出进度条
        printf("\r" COLOR_GREEN "[" COLOR_RESET);
        for (int j = 0; j < fill; ++j) printf("=");
        if (fill < BAR_LEN) printf(COLOR_YELLOW ">" COLOR_RESET);
        for (int j = fill + 1; j < BAR_LEN; ++j) printf(" ");
        printf("] ");

        // 输出详细信息:百分比、已完成/总量、速度、剩余时间
        printf(COLOR_YELLOW "%5.1f%%" COLOR_RESET "  ", percent);
        printf("%d/%d  ", i, total);
        printf(COLOR_CYAN "%.1f 个/秒" COLOR_RESET "  ", speed);
        printf("剩余: %d秒", eta);

        fflush(stdout);
        usleep(30000);  // 模拟每个任务单元的耗时
    }
    printf("\n");
    return 0;
}
实现逻辑说明
  1. 速度计算速度 = 已完成数量 / 已用时间
  2. 剩余时间估算ETA = (总量 - 已完成量) / 速度
  3. 使用 time() 函数获取系统时间,difftime() 计算时间差,单位为秒。
  4. 适合文件下载、批量处理、数据导入等真实业务场景。

四、版本 6:C++ 类封装工程版

将进度条封装为 ProgressBar 类,支持自定义样式、颜色、总长度,可直接嵌入项目复用

cpp 复制代码
#ifndef PROGRESS_BAR_H
#define PROGRESS_BAR_H

#include <string>
#include <time.h>

class ProgressBar {
public:
    // 构造函数:总任务量、进度条宽度、样式字符
    ProgressBar(int total, int width = 50, char fill_char = '=', char arrow_char = '>');

    // 更新进度:传入当前已完成量
    void update(int current);

    // 手动设置完成并换行
    void finish();

    // 是否已经完成
    bool is_finished() const { return finished_; }

private:
    int total_;       // 总任务量
    int width_;       // 进度条宽度
    char fill_char_;  // 填充字符
    char arrow_char_; // 箭头字符
    int current_;     // 当前完成量
    bool finished_;   // 是否完成
    time_t start_;    // 开始时间

    // 格式化时间显示
    std::string format_time(int seconds) const;
};

#endif
cpp 复制代码
#ifndef PROGRESS_BAR_H
#define PROGRESS_BAR_H

#include <string>
#include <time.h>

class ProgressBar {
public:
    // 构造函数:总任务量、进度条宽度、样式字符
    ProgressBar(int total, int width = 50, char fill_char = '=', char arrow_char = '>');

    // 更新进度:传入当前已完成量
    void update(int current);

    // 手动设置完成并换行
    void finish();

    // 是否已经完成
    bool is_finished() const { return finished_; }

private:
    int total_;       // 总任务量
    int width_;       // 进度条宽度
    char fill_char_;  // 填充字符
    char arrow_char_; // 箭头字符
    int current_;     // 当前完成量
    bool finished_;   // 是否完成
    time_t start_;    // 开始时间

    // 格式化时间显示
    std::string format_time(int seconds) const;
};

#endif

使用示例 main.cpp

cpp 复制代码
#include "progress_bar.h"
#include <unistd.h>

int main() {
    const int TOTAL = 500;
    ProgressBar bar(TOTAL, 60, '#', '>');

    for (int i = 0; i <= TOTAL; ++i) {
        bar.update(i);
        usleep(10000);
    }
    return 0;
}

编译运行:

cpp 复制代码
g++ main.cpp progress_bar.cpp -o progress_bar
./progress_bar

五、进阶扩展:旋转等待指示器

当任务总量未知、只能显示 "正在运行" 时,使用旋转字符动画(| / - \)替代进度条。

cpp 复制代码
#include <iostream>
#include <unistd.h>

int main() {
    const char spinner[] = {'|', '/', '-', '\\'};
    int idx = 0;

    std::cout << "正在处理中... ";
    for (int i = 0; i < 30; ++i) {  // 模拟30次循环
        printf("\b%c", spinner[idx % 4]);
        fflush(stdout);
        idx++;
        usleep(150000);
    }
    printf("\b完成\n");
    return 0;
}

六、核心总结与注意事项

  1. ANSI 转义序列是 Linux 终端美化的核心,所有主流终端均兼容。
  2. 工程化使用时建议封装为类,支持自定义样式、自动计算速度与 ETA。
  3. 总量未知场景可用旋转指示器替代固定进度条。
  4. 注意事项:
    • 重定向输出到文件时,ANSI 颜色码会变成乱码,生产环境可加判断禁用颜色。
    • 进度更新不要过于频繁(比如每毫秒刷新一次),避免占用过多 CPU。
    • 多线程环境下使用进度条需要加锁,防止输出错乱。

谢谢

相关推荐
orion579 小时前
Missing Semester Class1:course overview and introduction of shell
linux
SkyWalking中文站13 小时前
认识 Horizon UI · 6/17:Trace 探索器
运维·监控·自动化运维
用户1204872216115 小时前
Linux驱动编译与加载
linux·嵌入式
程序员老赵16 小时前
服务器文件不想 SFTP 上传?Docker 跑个 File Browser,浏览器就能管理
服务器·docker·开源
火车叼位16 小时前
写给初级开发者:SSL、SSH、HTTPS 与证书体系全解析
运维
vivo互联网技术21 小时前
从 10 分钟到 1 秒:ES 深度分页任意跳页的三轮优化实战
服务器·数据库·redis·elasticsearch·深度分页
用户8055336980321 小时前
Input 子系统架构:Core、Handler、Driver 三层是怎么协作的
linux·嵌入式
用户8055336980321 小时前
RK-Forge外设系列开篇 - 把板子从「能启动」变成「能用」:Ethernet/SPI/MMC 三个纯接线外设
linux·github·嵌入式
小猿姐1 天前
唯品会大规模数据库云原生实践:基于 KubeBlocks 管理数千实例的统一运维之路
运维·elasticsearch·云原生