Linux小程序 —— 进度条

简介: Linux小程序 —— 进度条

前言:经过这么多天的学习,想必大家学到了很多Linux知识,今天我们来用Linux来实现我们的第一个小程序 — — 进度条


本篇主要内容将会实现三个版本的进度条:

  • 简单原理版本
  • 实际工程实践版本
  • 拓展版本


1. 缓冲区的概念

我们先来分析下面几段代码感受一下行缓冲区的存在:

在Linux当中以下代码的运行结果是什么样的?

#include <stdio.h>
#include <unistd.h>                                                                                                                                                                    
  
int main()
{
    printf("你能看见我嘛\n");
    sleep(2);
    return 0;
}

这段代码运行结果显而易见:printf函数直接打印内容,然后休眠2秒。

对于大家可能没有什么难度。那如果我们修改一下代码。

#include <stdio.h>
#include <unistd.h>                                                                                                                                                                    
  
int main()
{
    printf("你能看见我嘛");
    sleep(2);
    return 0;
}

image.png 缓冲区的概念

通过视频我们发现,我仅仅是将\n删除了,但是却带来了完全不一样的运行结果:先休眠2秒,然后才是printf函数打印内容

那么为什么会出现这种情况呢? C语言执行代码的逻辑不应该是从上至下执行吗?

  • 按照 C语言执行代码的逻辑printf确实已经运行了,只不过内容没有被显示出来!
  • 内容所在的区域则是在输出缓冲区中!

C/C++语言,会针对标准输出,给我们提供默认的缓冲区

fflush函数可以刷新缓冲区,如果我们想立马显现可以用函数刷新fflush(),而\n是一种刷新的策略——行刷新,所以\n也能立马显现!


2. \r&&\n

概念:

  • \r: 回车,使光标回到本行首格
  • \n: 换行,使光标移到下一行

光说可能大家不太理解,我们来实操看看:

#include <stdio.h>
#include <unistd.h>

int main()
{
  int cnt = 10;
  while(cnt)
  {
    printf("%d\r", cnt--);
    fflush(stdout);
    sleep(1);
  }
  return 0;
}

image.png

回车 \r

我们可以看到在输出下一个数之前都让光标先回到本行首格。
但是为什么输出结果和我预想的完全不一样?

printf("%-2d\r", cnt--);

我们以两位字符进行输出,-则是表示靠左对齐,就可以正常输出了!


3. 进度条

在进行上面的铺垫之后,我们开始编写我们的第一个小程序。我们将用两个源文件和一个头文件,一个申明,一个调用,一个实现

test.c:实现

test.h:申明

main.c:调用

// Makefile:
mytest:test.c main.c
     gcc -o $@ $^
.PHONY:clean
clean:
     rm -rf mytest 



3.1 版本一

在版本一中,我们只要简单实现一下基本的功能,得到一个基本框架就足够了。

// process_v1

//test.h:申明
pragma once
#include <stdio.h>
#include <string.h>
#include <unistd.h>
  
// 定义进度条的总长度,因为有'\0'的存在所以设为101
#define SIZE 101 
// 定义进度条的当前进度
#define MAX_RATE 100
// 进度条的符号
#define STYLE '#'
// 进度条的休眠时间
#define STIME 1000*15

void process_v1();

.............

//test.c:实现
#include "test.h"
 
// 旋转光标
const char *str = "|/-\\";
// \\:才能表示一个'\'
void process_v1()
{
     int rate = 0;
     //初始化进度条全为'\0'
     char bar[SIZE] = {0};
   //循环打印
   int num = strlen(str);
     while(rate <= MAX_RATE)
     {
     // 进度条的打印格式
     // -100:先取好[]的范围,然后靠左打印。
         printf("[%-100s][%d%%][%c]\r", bar, rate, str[rate%num]);      
     // 刷新缓冲区                                                                                                                                   
         fflush(stdout);
     // 休眠时长
         usleep(STIME);
     // 填充符号
         bar[rate++] = STYLE;
     }
     // 刷新
     printf("\n");
 }

.............

//main.c:调用
#include "test.h>

int main()
{
  process();
  return 0;
}

image.png

进度条:版本一

我们的第一代进度条也就完成了,实现了基本的结构框架!而我们的进度条,肯定不能干自己的,一定是和某种任务关联起来的!


3.2 版本二

我们将循环改成内部维护一个简单的静态缓冲区,每次往缓冲区里面增加内容然后刷新缓冲区内容就可以

不能一次将进度条打印完毕,否则不能与场景更好的结合

// process_v2

//test.h:申明
#pragma once
 
#include <stdio.h>
#include <string.h>
#include <unistd.h>
  
#define SIZE 101
#define MAX_RATE 100
#define STYLE '#'
#define STIME 1000*15
 
typedef void(*callback_t)(int); // 回调函数        
// 这里我们也可以使用函数指针                                                                                                                                                                                    
void process_v2(int);                                 
~                            
.............
//main.c:调用
#include "test.h"
  
#define TARGET_SIZE 1024*1024 // 模拟下载软件的大小
#define DSIZE 1024*10 // 模拟下载的速度
  
//void download()
//{
//    int target = TARGET_SIZE; // 软件总体积
//    int total = 0; // 当前下载的大小
// 
//    while(total < target)
//    {
//        usleep(STIME); // 用休眠时间,模拟下载时间
//        total += DSIZE;
//       process_v2(total*100/target);                                                                                                                                                  
//    }
//    printf("\n");
//}
// 回调函数
void download(callback_t cb)
{
    int target = TARGET_SIZE; // 软件总体积
    int total = 0; // 当前下载的大小
 
    while(total < target)
    {
        usleep(STIME); // 用休眠时间,模拟下载时间
        total += DSIZE;
        int rate = total*100/target;   
        cb(rate);                                                                                                                                               
    }
    printf("\n");
 }
  
int main()
{
    download(process_v2);
    return 0;
}
.............
//test.c:实现
#include "test.h"
  
const char *str = "|/-\\";

void process_v2(int rate)
{
    static char bar[SIZE] = {0};
    int num = strlen(str);
    
    if(rate <= MAX_RATE && rate >= 0)                                                                                                                                                  
    {
        printf("[%-100s][%d%%][%c]\r", bar, rate, str[rate%num]);
        fflush(stdout);
        bar[rate] = STYLE;
    }
    if(rate == MAX_RATE)
    {
        // 重新刷新为0
        memset(bar, '\0', sizeof(bar));
    }
}

image.png

进度条:版本二

我们也能完成进度条的实现,最后我们在优化一下,变成我们的版本三!。


3.3 版本三

因为版本二已经能将进度条完美的呈现了,我们版本三,只是在二的基础上,美化一下,所以只是简单修改一点代码!

// test.h
#define STYLE_DEADER '>'
#define STYLE_BODY '='

typedef void (*callback_t)(double);

.............

// main.c
// 我们在下载时,模拟下载中断的状态
void download(callback_t cb)
{
    int target = TARGET_SIZE; // 软件总体积
    int total = 0; // 当前下载的大小
 
    while(total <= target)
    {
        usleep(STIME); // 用休眠时间,模拟下载时间
        total += DSIZE;
        double rate = total*100/target; 
        // 我们让下载进度永远维持在50%左右
        if(rate > 50.0)
        {
          total = target/2;
        }  
        cb(rate);                                                                                                                                               
    }
    printf("\n");
 }
 
.............

// test.c
 if(rate <= MAX_RATE && rate >= 0)
 {
    // 设置cnt是为了在下载终止时,光标依然能变化
    cnt++;
    cnt = cnt > num ? 0 : cnt;
    // \033[1;47;30m ... \033[0m 则是更改输出时字体和背景颜色
    printf("加载中...\033[1;47;30m%-100s\033[0m][%.1lf%%][%c]\r", bar, rate, str[cnt]);                                                       
    fflush(stdout);
    if(rate < MAX_RATE)
    {
        bar[(int)rate] = STYLE_BODY;
        bar[(int)rate+1] = STYLE_HEADER;
    }
    else{
           bar[(int)rate] = STYLE_BODY;
    }
 }

image.png

进度条:版本三

我们可以发现,我们修改了字体颜色和背景,设置测试了可能遇到的中断情况,光标依旧会变化。当然了进度条还有很多情景,等待着各位开发!


4. 总结拓展

拓展:

关于print带颜格式化输出,我在这里推荐一篇博客,有兴趣的可以去了解一下

print带颜格式化输出


总结:

本篇我们简单了解了一下缓冲区,以及换行'\n'与回车'\r'的基本概念,然后由浅入深的介绍了三个版本的进度条,当然了美化方式各位都不一样,都是可以的,我们的Linux第一个小程序就讲到这里

谢谢大家支持本篇到这里就结束了


目录
相关文章
|
7月前
|
缓存 小程序 Linux
【Linux】Linux第一个小程序-进度条
【Linux】Linux第一个小程序-进度条
|
7月前
|
小程序 Linux 开发工具
【Linux】Linux 开发工具(vim、gcc/g++、make/Makefile)+【小程序:进度条】-- 详解
【Linux】Linux 开发工具(vim、gcc/g++、make/Makefile)+【小程序:进度条】-- 详解
|
4月前
|
Linux 开发工具
linux下使用gcp拷贝数据的时候显示进度条
linux下使用gcp拷贝数据的时候显示进度条
34 2
|
5月前
|
小程序
【亲测有效】支持横竖屏 微信小程序video禁止进度条拖动,微信小程序遮罩进度条,
【亲测有效】支持横竖屏 微信小程序video禁止进度条拖动,微信小程序遮罩进度条,
94 1
【亲测有效】支持横竖屏 微信小程序video禁止进度条拖动,微信小程序遮罩进度条,
|
6月前
|
Linux
【make/Makefile】Linux下进度条的设计与实现
【make/Makefile】Linux下进度条的设计与实现
|
7月前
|
数据可视化 小程序 Linux
【Linux】6. 实现进度条和git基本认识和使用
【Linux】6. 实现进度条和git基本认识和使用
64 4
|
1月前
|
小程序 前端开发 JavaScript
在线课堂+工具组件小程序uniapp移动端源码
在线课堂+工具组件小程序uniapp移动端源码
34 0
在线课堂+工具组件小程序uniapp移动端源码
|
2月前
|
移动开发 小程序 数据可视化
基于npm CLI脚手架的uniapp项目创建、运行与打包全攻略(微信小程序、H5、APP全覆盖)
基于npm CLI脚手架的uniapp项目创建、运行与打包全攻略(微信小程序、H5、APP全覆盖)
342 3
|
2月前
|
小程序 API
微信小程序更新提醒uniapp
在小程序开发中,版本更新至关重要。本方案利用 `uni-app` 的 `uni.getUpdateManager()` API 在启动时检测版本更新,提示用户并提供立即更新选项,自动下载更新内容,并在更新完成后重启小程序以应用新版本。适用于微信小程序,确保用户始终使用最新版本。以下是实现步骤: ### 实现步骤 1. **创建更新方法**:在 `App.vue` 中创建 `updateApp` 方法用于检查小程序是否有新版本。 2. **测试**:添加编译模式并选择成功状态进行模拟测试。
57 0
微信小程序更新提醒uniapp
|
4月前
|
小程序 前端开发 Java
SpringBoot+uniapp+uview打造H5+小程序+APP入门学习的聊天小项目
JavaDog Chat v1.0.0 是一款基于 SpringBoot、MybatisPlus 和 uniapp 的简易聊天软件,兼容 H5、小程序和 APP,提供丰富的注释和简洁代码,适合初学者。主要功能包括登录注册、消息发送、好友管理及群组交流。
116 0
SpringBoot+uniapp+uview打造H5+小程序+APP入门学习的聊天小项目