【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;
}                                                                                                                                         
相关推荐
这儿有一堆花35 分钟前
Kali Linux:探测存活到挖掘漏洞
linux·运维·服务器
松涛和鸣41 分钟前
从零开始理解 C 语言函数指针与回调机制
linux·c语言·开发语言·嵌入式硬件·排序算法
Ccjf酷儿42 分钟前
操作系统 蒋炎岩 3.硬件视角的操作系统
笔记
习习.y1 小时前
python笔记梳理以及一些题目整理
开发语言·笔记·python
在逃热干面2 小时前
(笔记)自定义 systemd 服务
笔记
皮小白2 小时前
ubuntu开机检查磁盘失败进入应急模式如何修复
linux·运维·ubuntu
邂逅星河浪漫2 小时前
【CentOS】虚拟机网卡IP地址修改步骤
linux·运维·centos
hhwyqwqhhwy2 小时前
linux 驱动开发相关
linux·驱动开发
IT逆夜3 小时前
实现Yum本地仓库自动同步的完整方案(CentOS 7)
linux·运维·windows
a***59263 小时前
用nginx正向代理https网站
运维·nginx·https