当前位置: 首页 > news >正文

【Linux中的第一个小程序】进度条及printf打印彩色字符

在这里插入图片描述

📃博客主页: 小镇敲码人
💚代码仓库,欢迎访问
🚀 欢迎关注:👍点赞 👂🏽留言 😍收藏
🌏 任尔江湖满血骨,我自踏雪寻梅香。 万千浮云遮碧月,独傲天下百坚强。 男儿应有龙腾志,盖世一意转洪荒。 莫使此生无痕度,终归人间一捧黄。🍎🍎🍎
❤️ 什么?你问我答案,少年你看,下一个十年又来了 💞 💞 💞

Linux中的第一个小程序进度条

  • \n和\r
    • 倒计时程序
      • 缓冲区
      • 倒计时程序
    • 不同平台的行结束符
  • 进度条程序的编写
    • 版本1 简易版
    • 版本2 增强版
    • printf打印彩色字体

前几篇博客介绍了C/C++中Linux系统常用的开发工具,今天这篇博客来介绍Linux中的第一个小程序进度条。

\n和\r

  • \n是换行符:它会将光标下移一行。
  • \r是回车符:它会将光标移动到行首位置。

下面的倒计时程序加深你对\r回车符的认识。

倒计时程序

在写倒计时程序之前,我们先来谈一谈缓冲区的概念。

缓冲区

缓冲区是Linux中的一种机制,我们今天只简单介绍一下,它是一个文件用于存储内容,常见的有输入缓冲区和输出缓冲区。Linux中是先把一行中打印的内容存在输出缓冲区中,这样可以减少访问输出设备的次数,提高效率,等程序运行结束,或者遇到\n符或者一行写满,内容就会从输出缓冲区中刷新出来打印在显示器文件上。

看下面代码,思考为什么会这样:

#include <unistd.h>     
#include<stdio.h>int main()
{printf("hello gcc!\n");printf("hello Linux!");printf("hello Linux!");printf("hello Linux!");printf("hello Linux!");sleep(5);return 0;
}

Linux平台会出现什么现象呢?只有第一个printf会马上打印出来,在sleep休眠期间,其余的printf肯定早就跑完了,因为程序是顺序执行的,输出的字符串一定被保存到了一个地方,这个地方就是输出缓冲区,要等程序运行结束才会从缓冲区里面刷新出来:

20241031_09_40_52_880

  • 每当遇到换行符时,缓冲区中的数据会被刷新到目标设备。所以第一个printf的内容会被刷新出来打印在显示器上,另外几个printf由于没有遇见换行符,它们都是一行的内容,要等程序结束才会被一起刷新出来。

倒计时程序

#include <unistd.h>                                                             
#include<stdio.h>                                                                                                                                                                                                       
int main()                                                                      
{                                                                      for(int i = 10;i >= 0;i--)                                             {                                                                     printf("%-2d\r",i);                                                fflush(stdout);                                                     sleep(1);                                                           }                                                                     return 0;                                                             
}    
  • fflush函数是用来刷新缓冲区的,由于一行的内容需要写满或者\n才会被刷新出来,所以我们需要,fflush函数刷新缓冲区,上面已经介绍过了。\r是回车符,会将光标移动到最开始,所以我们能将原先打印在屏幕上的内容覆盖。

运行结果:

1730288373765

  • %-2d意味着以左对齐的方式输出一个至少占2个字符宽度的十进制整数,如果是一位,会填充空格,把之前显示在显示器上的内容覆盖,如果没有这个就会有内容没有被覆盖:

    20241031_10_09_55_295

不同平台的行结束符

我们这里的行结束符是指的是具有回车和换行两个功能的符号,等效于Enter键。

image-20241031101202755

Enter键的符号就很明显,先换行,再回车,实际上是两步。

以下是一个关于不同平台行结束符的总结表格:

不同平台行结束符总结表格

平台行结束符描述
Unix/Linux\n (LF)换行符,表示当前行的结束和新行的开始
Windows\r\n (CRLF)回车换行符,先回车(光标回到行首)再换行(光标移动到下一行)
Mac OS 9及之前\r (CR)回车符,单独用作行结束符
Mac OS X及之后(包括macOS)\n (LF)与Unix/Linux相同,换行符

VS2019你会发现只用\n也有行结束符的效果,这是是因为它具有内部处理机制来转换行结束符、允许用户通过编辑器设置指定行结束符类型,并且可能使用了广泛认可的文本处理库来处理不同平台的行结束符。

  • Windows自带的文本编辑器查看行结束符是行的,我们可以借助工具Notepad++

    • 下载安装Notepad++

    • 打开要显示的文本文件。

    • 点视图,勾选显示符号中的显示行尾,就可以查看行结束符:

      image-20241031104630905

    • CRLF就是\r\n,这是Windows系统处理文本行尾的标准方式。

  • 我们还可以验证Linux中的行结束符,只需要在Linux中创建一个文本文件,然后传到Windows中,继续使用这个软件即可。

    • Linux系统上创建文本文件:

      image-20241031105048073

    • 写入内容 。

      image-20241031105150144

    • 使用指令sz 文件的路径,将文件快速传到Windows中。需要安装软件lrzsz,这里Windows中接收的文件夹我们选择桌面即可。

      image-20241031105305269

    • 传输完成之后,使用Notepad++打开该文件。

      image-20241031111029148

虽然Windows自带的行结束符,不能在文本文件查看器中直接显示行结束符,但是状态栏显示了它的行结束符的类型:

image-20241031111229828

进度条程序的编写

版本1 简易版

下面是简易版的进度条,没有加颜色,也没有模拟真实的情况。

progress.c:

#include"progress.h"                                                    
const char* lable = "|/-\\";                                             
//version1                                                              
void process1()                                                         
{                                                                       char buffer[NUM];                                                     int cnt = 0;                                                           memset(buffer,'\0',sizeof(buffer[0])*NUM);                             int n = strlen(lable);                                                 buffer[0] = Head;                                                     while(cnt <= 100)                                                     {                                                                     printf("%-100s%3d%%%c\r",buffer,cnt,lable[cnt%5]);   usleep(50000);fflush(stdout);                                                     buffer[cnt++] = Body;                                               if(cnt < 100)                                                       buffer[cnt] = Head;                                             }                                                 
}                 

progress.h

#ifndef _PROGRESS_H_                                                                                                                                                       
#define  _PROGRESS_H_                                                                
#include <time.h>                                                                    
#include<stdio.h>                                                                    
#include <stdlib.h>                                                                  
#include<string.h>                                                                   
#include<unistd.h>                                                                   
#define Head '>'                                                                     
#define Body '='                                                                     
#define NUM 103                                                                      
//version1                                                                           
void process1();                                                                                               
#endif    

main.c

#include"progress.h"                                                            
int main()                                                                           
{                                                                                           process1();                                                                      
} 

运行结果:

20241102_10_22_26_471

  • usleep函数是Linux系统中用于延时的函数,它会想程序挂起暂停执行,它是微秒级别的。

    image-20241102102626442

    • 在使用这个函数的时候,需要包含头文件unistd.h
  • 想要打印出一个实际的百分号字符,而不是一个格式说明符,需要使用两个百分号来“转义”它。

版本2 增强版

此版本模拟实际的下载过程,进度条的进度不应该由进度条自己决定而应该由下载的程序决定,另外还增加了颜色的打印。

main.c:

#include"progress.h"                                                            #define FILESIZE 1024*1024*1024                                                 void download(call_back cb)                                                     
{                                                                               srand(time(NULL)^1023);                                                       int total = FILESIZE;                                                         while(total)                                                                  {                                                                             usleep(10000);//下载动作                                                      int one = rand()%(1024*1024*10);                                              total -= one;                                                                 if(total < 0)                                                                 total = 0;                                                                int download = FILESIZE-total;                                                double rate = (download*1.0)/(FILESIZE)*100.0;                                cb(rate);                                                                     }                                                                             
}         int main()                                                                      
{ download(call_back);                                                                 
}                                                                               

progress.c

#include"progress.h"                                                    
const char* lable = "|/-\\";  char buffer[NUM] = {0};                                                         
//version2                                                                      
void process_flush(double rate)                                                 
{                                                                               static int cnt = 0;                                                          if(rate <= 1.0)                                                              buffer[0] = Head;                                                          int n = strlen(lable);                                                       printf("\033[43;31;1;7m%-100s\033[0m%3lf%%%c\r",buffer,rate,lable[cnt%n]);          fflush(stdout);                                                              buffer[(int)rate] = Body;                                                    if((int)rate+1 < 100)                                                        buffer[(int)(rate+1)] = Head;                                            if(rate >= 100.0)                                                            printf("\n");                                                            cnt++;                                                                        cnt %= n;                                                                     
} 

progress.h:

#ifndef _PROGRESS_H_                                                                                                                                                       
#define  _PROGRESS_H_                                                                
#include <time.h>                                                                    
#include<stdio.h>                                                                    
#include <stdlib.h>                                                                  
#include<string.h>                                                                   
#include<unistd.h>                                                                   
#define Head '>'                                                                     
#define Body '='                                                                     
#define NUM 103                                                                      //version2                                                                           
void process_flush(double);                                                          typedef void (*call_back)(double);                                                   
#endif        

运行结果:

20241102_10_44_35_224

  • 我们控制了下载速度,使其每一次调用process_flush最多增加1%实际情况可能更复杂。

  • cnt是控制转动的标的,它是static变量不会一直被初始化,所以lable数组的下标会一直变化,下载速度不影响它的状态,这告诉用户我们的程序一直在运行,一直在尝试下载,如果不加static就是这样:

    20241102_10_55_13_174

    • 旋转的标不再旋转,因为cnt会被重新初始化为0,lable数组的下标没变,打印的符号也不会变化。

printf打印彩色字体

基本语法:

在C语言中,使用printf函数打印彩色字符时,可以通过嵌入ANSI转义序列来实现。这些转义序列由特定的控制命令组成,包括以\033[开头、以m结尾的部分,中间则是属性码,属性代码之间使用;分隔。

printf("\033[属性代码1;属性代码2;属性代码3....m 待写的占位符",占位符填充的变量)

常见的属性代码,我们下面用表格总结一下:

属性类别属性代码功能描述示例
通用格式控制0重置所有属性\033[0m
1高亮/加粗\033[1m
2暗淡\033[2m
4下划线\033[4m
5闪烁\033[5m
7反转\033[7m
8隐藏\033[8m
前景色(文字颜色)30黑色\033[30m
31红色\033[31m
32绿色\033[32m
33黄色\033[33m
34蓝色\033[34m
35品红\033[35m
36青色\033[36m
背景色40黑色\033[40m
41红色\033[41m
42绿色\033[42m
43黄色\033[43m
44蓝色\033[44m
45品红\033[45m
46青色\033[46m

我们举几个例子来使用一下:

  1. 打印两行,要求第一行闪烁加粗背景色为青色文字颜色为红色,第二行为下划线,背景色为蓝色,文字颜色为品红,内容随意。
#include<stdio.h>int main()
{printf("\033[1;5;46;31m hello world!!! \n \033[0m");printf("\033[4;44;35m hello Linux!!! \033[0m");return 0;
}

20241102_11_23_47_477

  • \033[0m:是重置所有属性,防止这次的内容影响到下面的打印。
  • 本人知识、能力有限,若有错漏,烦请指正,非常非常感谢!!!
  • 转发或者引用需标明来源。

http://www.mrgr.cn/news/64096.html

相关文章:

  • 线性代数【考研准备 基于教材 期末复习亦可用】第一章行列式
  • JavaIO流操作
  • 2024 Rust现代实用教程:Ownership与结构体、枚举
  • 代码随想录 -- 动态规划 -- 不同路径 II
  • 使用 Cloudreve 搭建你的专属个人网盘
  • Vue中ref、reactive、toRef、toRefs的区别
  • 《Python修炼秘籍》01踏上编程之旅
  • 满秩分解与奇异值分解
  • 机器人大模型GR2——在大规模视频数据集上预训练且机器人数据上微调,随后预测动作轨迹和视频(含GR1详解)
  • 树的遍历(先,中,后)
  • 【无人机设计与控制】改进无人机三维路径规划(蜣螂优化算法)Matlab程序
  • 除甲醛开窗通风的正确方法 消除甲醛的最好方法
  • 如何引用一个已经定义过的全局变量?
  • 【含文档】基于ssm+jsp的智慧篮球馆预约(含源码+数据库+lw)
  • 【含文档】基于Springboot+Vue的工商局商家管理系统 (含源码数据库+LW)
  • 基于javaweb(springboot+mybatis)网站建设服务管理系统设计和实现以及文档报告设计
  • ssm毕业设计选题系统+jsp
  • HTML 基础标签——表格标签<table>
  • cangjie仓颉程序设计-怎么排序(二)
  • 从头开始学PHP之面向对象
  • 2025生物发酵展(济南)为生物制造产业注入新活力共谱行业新篇章
  • 仓颉刷题录-二维数组(二)
  • 第15届蓝桥杯省赛真题剖析-2024年8月24日Scratch中级组
  • 使用Github下载YOLO v5项目教程
  • 面试题:JVM(六)
  • TOP级AI驱动的单元测试工具推荐