一、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:彩色动态进度条
加入绿色进度条、百分比高亮、完成后变色提示,视觉效果大幅提升。
#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),是工程中最实用的版本。
#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; }实现逻辑说明
- 速度计算:
速度 = 已完成数量 / 已用时间 - 剩余时间估算:
ETA = (总量 - 已完成量) / 速度 - 使用
time()函数获取系统时间,difftime()计算时间差,单位为秒。 - 适合文件下载、批量处理、数据导入等真实业务场景。
四、版本 6:C++ 类封装工程版
将进度条封装为ProgressBar类,支持自定义样式、颜色、总长度,可直接嵌入项目复用
#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#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
#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; }编译运行:
g++ main.cpp progress_bar.cpp -o progress_bar ./progress_bar五、进阶扩展:旋转等待指示器
当任务总量未知、只能显示 “正在运行” 时,使用旋转字符动画(| / - \)替代进度条。
#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; }六、核心总结与注意事项
- ANSI 转义序列是 Linux 终端美化的核心,所有主流终端均兼容。
- 工程化使用时建议封装为类,支持自定义样式、自动计算速度与 ETA。
- 总量未知场景可用旋转指示器替代固定进度条。
- 注意事项:
- 重定向输出到文件时,ANSI 颜色码会变成乱码,生产环境可加判断禁用颜色。
- 进度更新不要过于频繁(比如每毫秒刷新一次),避免占用过多 CPU。
- 多线程环境下使用进度条需要加锁,防止输出错乱。