【Linux】LInux下第一个程序:进度条

前言:

在前面的文章中我们学习了LInux的基础指令

【Linux】初见,基础指令-CSDN博客【Linux】初见,基础指令(续)-CSDN博客

学习了vim编辑器【Linux】vim编辑器_linux vim insert-CSDN博客

学习了gcc/g++【Linux】编译器gcc/g++及其库的详细介绍-CSDN博客

以及make/makefile【Linux】自动化构建-Make/Makefile-CSDN博客

有了以上知识的铺垫,我们终于可以开始在Linux上编写运行我们的代码,于是我们来到了Linux下的第一个程序:进度条

1.回车换行符

大多数人可能觉得"回车换行"这一词指的是同一个东西。但其实回车是回车、换行是换行,这两个有本质区别。

我们日常使用的回车键合成了"回车"和"换行"功能,这就导致了大家觉得这是一个东西。

回车的符号为:\n
回车的功能是将光标重置到最开始位置

换行的符号为:\r
换行的功能是将光标下移一行

2.缓冲区问题

什么是缓冲区?

缓冲区是系统预留的内存区域,其作用是暂时存放输入或输出的数据。引入缓冲区主要是为了平衡高速的 CPU 与低速的 I/O 设备之间的速度差异,进而提升系统的整体性能。

刷新缓冲区?

通常情况下,数据会先被存储在缓冲区中,只有当缓冲区满、遇到特定的控制字符,或者程序运行结束时,才会将数据真正写入目标设备。不过,在某些特定场景下,可能需要手动刷新缓冲区,以确保数据能及时输出。

举例:

复制代码
//代码1
#include<stdio.h>
#include<unistd.h>
int main()
{

    printf("hello\n");                                                                                                                                       
    sleep(3);    
}


//代码2
#include<stdio.h>
#include<unistd.h>
int main()
{                                                                                                                            
    printf("hello");
    sleep(3);    
}

运行代码1:我们可以看到显示屏上马上显示出"hello",然后停滞3秒结束程序

运行代码2:我们看到是恰恰相反,先停滞3秒后打印出"hello",然后结束程序

这个就是缓冲区的问题:"\n"可以马上刷新缓冲区,所以代码1可以马上显示。而没有"\n",就无法马上刷新缓冲区,当整个程序结束后系统自动刷新,显示"hello"

那如何使其马上刷新?

复制代码
fflush(stdout)

3.预备代码

先创建文件夹,并在文件夹中创建相应的.c .h文件

复制代码
hyc@hcss-ecs-4ce7:~$ mkdir progress
hyc@hcss-ecs-4ce7:~$ cd progress
hyc@hcss-ecs-4ce7:~/progress$ touch p.c p.h main.c

编写代码,与makefile。进度条只会在一行打印,所以我们不能使用 \n,而是使用 \r,在同一行打印

但是当我们运行代码时,发现并没有显示结果。这是因为当前数据还在缓冲区没有刷新出来,我们使用ffulsh(stdout)使其马上刷新

这时我们可以看到结果:在同一位置上显示

4.进度条代码

4.1首先先看看我们想实现一个什么样子的进度条

4.2代码实现

我们一步一步来,先实现左侧部分

1.考虑使用字符数组来表示递增的进度条。先将字符数组初始化为 '\0',通过%s打印时遇到 '\0'就会停止。

2.通过计数器计数,来计算输出多少符号

3.通过fflush(stdout)立马刷新缓冲区,让我们看到结果

4.通过sleep让我们看到其过程

5.最后为了避免命令行覆盖我们输出的内容,进行换行操作

最后添加一下左右中括号,修改一下细节问题:

打印进度条使用%-100s占位符

sleep有点太慢了,我们可以使用usleep

复制代码
#include"p.h"
#include<unistd.h>
#include<string.h>

void progress_v1()
{
    char arr[101];
    memset(arr,'\0',sizeof(arr));
    int num=0;
    for(int i=0;i<=101;i++)
    {   
        arr[num]='X';
        printf("[%-100s]\r",arr);
        fflush(stdout);
        usleep(10000);
        num++;
    }   
    printf("\n");
}  

效果

接下来我们就可以来考虑一下百分比和旋转光标了

1.百分比直接去计算就好了,没什么好说的。

2.旋转光标:我们不要去想复杂了,动态的本质其实就是一帧一帧的静态图像,我们只需要写一个字符数组x,然后不断的打印字符,就可以实现旋转光标了。

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

void progress_v1()
{
    char arr[101];
    char x[]={'/','-','\\','\0'};
    memset(arr,'\0',sizeof(arr));
    int num=0;
    for(int i=0;i<=101;i++)
    {   
        arr[num]='X';
        printf("[%-100s][%.2f][%c]\r",arr,num*1.0/sizeof(arr)*100,x[num%3]);
        fflush(stdout);
        usleep(10000);
        num++;
    }   
    printf("\n");
}  

效果演示:

5.模拟真实环境

一个真正的进度条不可能就我们上面写的代码一样自顾自的打印。应该是根据实际情况,一边下载(或其他操作),一边打印进度条。

于是我们实现一个download函数模拟实时下载环境:

total:表示一共想要下载的量

speed:表示单次下载的速度

每下载一次就更新一次进度条

通过实时的下载量来计算进度条中需要打印的个数,以及百分比。

代码汇总:

复制代码
//p.h

#include<stdio.h>
void progress_v1();
void progress_v2(double cur,double total);        


//p.c

#include"p.h"
#include<unistd.h>
#include<string.h>

void progress_v1()
{
    char arr[101];
    char x[]={'/','-','\\','\0'};
    memset(arr,'\0',sizeof(arr));
    int num=0;
    for(int i=0;i<=101;i++)
    {
        arr[num]='X';
        printf("[%-100s][%.2f][%c]\r",arr,num*1.0/sizeof(arr)*100,x[num%3]);
        fflush(stdout);
        usleep(10000);
        num++;
    }   
    printf("\n");
}

void progress_v2(double cur,double total)
{
    char arr[101];
    char x[]={'/','-','\\','\0'};
    memset(arr,'\0',sizeof(arr));
    
    //get the number
    int num=(int)(cur*100/total);
    for(int i=0;i<num;i++)
    {   
        arr[i]='X';
    }   
                                                                                                                                                             
    printf("[%-100s][%.2f][%c]\r",arr,cur*100/total,x[num%3]);
    fflush(stdout);
}


//main.c

#include <stdio.h>
int main()
{
    printf("Hello world\n");
    return 0;
}                                                                                                                                         
相关推荐
盟接之桥1 小时前
盟接之桥说制造:在安全、确定与及时之间,构建品质、交期与反应速度的动态平衡
大数据·运维·安全·汽车·制造·devops
learning_tom1 小时前
HTML图片标签及路径详解
linux·服务器·php
Suckerbin2 小时前
DarkHole: 2靶场渗透
笔记·安全·web安全·网络安全
dbdr09012 小时前
Linux 入门到精通,真的不用背命令!零基础小白靠「场景化学习法」,3 个月拿下运维 offer,第二十六天
linux·运维·服务器·网络·python·学习
一枝小雨2 小时前
【C++】Vector完全指南:动态数组高效使用
开发语言·c++·笔记·vector·学习笔记·std库
大白的编程日记.2 小时前
【Linux学习笔记】信号的深入理解之软件条件产生信号
linux·笔记·学习
鹧鸪云光伏与储能软件开发2 小时前
投资储能项目能赚多少钱?小程序帮你测算
运维·数据库·小程序·光伏·光伏设计软件·光伏设计
群联云防护小杜2 小时前
服务器异常磁盘写排查手册 · 已删除文件句柄篇
运维·服务器·nginx·开源·lua
buyutang_2 小时前
C/C++ Linux系统编程:线程控制详解,从线程创建到线程终止
linux·c语言·c++·学习
Wilber的技术分享3 小时前
【大模型实战笔记 1】Prompt-Tuning方法
人工智能·笔记·机器学习·大模型·llm·prompt