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。
    • 多线程环境下使用进度条需要加锁,防止输出错乱。

谢谢

相关推荐
李小白661 小时前
第四天-WEB服务器基本原理,IIS服务
运维·服务器·前端
2401_834636992 小时前
Nginx 从入门到实战:静态 / 动态站点、PHP 部署与反向代理全解析
运维·nginx·php
爱喝水的鱼丶2 小时前
SAP-ABAP:SAP视图开发入门:四类标准视图的适用场景与创建步骤详解
服务器·数据库·性能优化·sap·abap
aosky3 小时前
一台电脑配置多个 SSH Key 对应不同的 GitHub 账号
运维·ssh·github
云登指纹浏览器4 小时前
WebDriver反检测技术详解:如何让自动化脚本看起来像真实浏览器
运维·自动化·跨境电商
xmtxz4 小时前
计算机网络基础课程学习心得:从理论抽象到硬核实战的进阶之路
运维·学习
凡人叶枫4 小时前
Effective C++ 条款17:以独立语句将 newed 对象置入智能指针
java·linux·开发语言·c++·算法
RisunJan4 小时前
Linux命令-pgrep (通过进程名查找进程 ID)
linux·运维
回忆2012初秋5 小时前
【Nginx】优雅地走进高性能 Web 服务器世界(1)
服务器·前端·nginx