【Linux】9.Linux第一个小程序进度条

devtools/2025/1/17 18:13:49/

文章目录

  • Linux第一个小程序-进度条
    • 相关知识
    • 创建程序
      • 1. 程序原理
      • 2. 基础程序原理实现
    • 井号进度条代码实现
    • 箭头进度条代码实现
    • 多重进度条代码实现


Linux第一个小程序-进度条

相关知识

特殊符号:

$@$^

回车换行:

回车和换行其实是两个东西。

回车:挪到下一行的最前面。

换行:挪到下一行的当前位置,就是从上往下。

缓冲区:


创建程序

1. 程序原理

我们先创建一个文件夹,进去

90fba84f0e0005c99c57ff6c2367442b

然后创建3个文件

3d4f2bd15e379210a78b12b490666269

然后进入processBar.h,写一下

877c447368658d92654537194d4eb6c0

然后往main.c里面写一点东西。

c331c2e83fc18a04d7e652db18560d93

然后创建makefile文件,进去编写代码

processbar:processBar.c main.cgcc -o $@ $^
.PHONY:clean
clean:rm -f processbar

然后进入main.c,修改代码

# include "processBar.h"
#include <unistd.h>int main()
{printf("hello world\n");sleep(2);//这个要用到unistd.h头文件return 0;
}

现象是先打印hello world,然后休眠2s

12b5ff537a50e0491b6f7cf95a198c2e

然后进入main.c,修改代码,去掉\n,那么现象会是什么呢?

是先打印hello world,然后休眠2s还是先休眠2s,然后打印hello world呢?

# include "processBar.h"
#include <unistd.h>int main()
{printf("hello world");//1sleep(2);             //2return 0;
}

得到的现象是先休眠2s,然后打印hello world

eb201771774b8b54f0d77dee2e50e78b

咦,怎么会这样?难道先执行了第二条语句,然后执行第一条语句吗?

当然不是。

C语言是按顺序执行的,所以执行顺序一定是先执行第一条语句,再执行第二条语句。

那为什么会这样呢?

sleep期间,printf语句执行完了,那么它在这两秒内怎么了呢?

因为后面还是打印出来了,说明printf一定被保存起来了。

保存在了C语言的缓冲区,这个缓冲区就是指由C语言维护的一段内存。

如果我要强制刷新呢?

C语言文件默认打开3个文件:标准输入流,标准输出流(显示器显示),标准错误流

我们继续更改一下main.c文件,添加一行代码:

# include "processBar.h"
#include <unistd.h>int main()
{printf("hello world");//1fflush(stdout); // 强制刷新标准输出缓冲区sleep(2);             //2return 0;
}

再次运行的结果就不一样了,现象是先打印hello world,然后休眠2s

关键点解释:

  1. printf("hello world");

    • 将字符串输出到标准输出
    • 但由于缓冲机制,不一定立即显示在屏幕上
    • 内容可能暂存在缓冲区中
  2. fflush(stdout);

    • 强制刷新标准输出缓冲区
    • 确保"hello world"立即显示在屏幕上
    • 不使用fflush时,内容可能要等到缓冲区满或程序结束才显示
  3. sleep(2);

    • 让程序暂停执行2秒
    • 单位是秒
    • 这期间程序什么都不做

如果去掉fflush(stdout)

  • "hello world"可能要等到程序结束才显示
  • 因为程序很快就结束了,用户可能看不到2秒暂停的效果

2. 基础程序原理实现

好的 ,通过上面的原理,应该都知道了缓冲区的存在了。

比如我们输入一个9,那么光标就跑到9的后面了。

我们在9的前面输入一个8,那么9就被挤到8的后面了,得到了89

我们进入main.c文件,更改一下代码:

# include "processBar.h"
#include <unistd.h>int main()
{//倒计时int cnt = 9;while(cnt){printf("%d",cnt);fflush(stdout);cnt--;sleep(2);}//printf("hello world");//1//fflush(stdout);//sleep(2);             //2return 0;
}

得到:

b07e42583ece2d6294df12f83d6dd4d9

43cbffbaa39a4330624b2044569c5818

4a2b6f1abb1bf292c2d637de58fa8baa

但是这个不是让光标回到最开始写的,怎么修改呢?

我们加个\r就可以了

# include "processBar.h"
#include <unistd.h>int main()
{//倒计时int cnt = 9;while(cnt){printf("%d\r",cnt);fflush(stdout);cnt--;sleep(2);}printf("\n");//printf("hello world");//1//fflush(stdout);//sleep(2);             //2return 0;
}

打印:

b60153092e70e314bb16095bb84aef14

1e48f466b5808fb11869c7574bd5be01

实现了一个简单的倒计时。

不过表面上看起来我们实现的很完美,可是如果倒计时变成两位数的话:

# include "processBar.h"
#include <unistd.h>int main()
{//倒计时int cnt = 10;while(cnt>=0){printf("%d\r",cnt);fflush(stdout);cnt--;sleep(2);}printf("\n");//printf("hello world");//1//fflush(stdout);//sleep(2);             //2return 0;
}

程序打印为:

10 --> 90 -->80。。。

因为打印的是字符。

这里我们只需要加一个-2就可以了,%-2d一次打印两个字符,而且是左对齐。

# include "processBar.h"
#include <unistd.h>int main()
{//倒计时int cnt = 10;while(cnt>=0){printf("%-2d\r",cnt);fflush(stdout);cnt--;sleep(2);}printf("\n");//printf("hello world");//1//fflush(stdout);//sleep(2);             //2return 0;
}

井号进度条代码实现

processBar.c

#include "processBar.h"
#include <string.h>
#include <unistd.h>const char *lable="|/-\\";void processbar()
{char bar[NUM];memset(bar,'\0',sizeof(bar));int len=strlen(lable);int cnt=0;while(cnt<=100){printf("[%-100s][%d%%][%c]\r",bar,cnt,lable[cnt%len]);fflush(stdout);bar[cnt++]=STYLE;usleep(100000);}printf("\n");
}

processBar.h

#pragma once#include <stdio.h>#define NUM 102
#define STYLE '#'extern void processbar();

main.c

# include "processBar.h"
#include <unistd.h>int main()
{processbar();return 0;
}

实现效果:

cf69253f3299694ed79d6a0caec61cd9

0d0d1dfdd1fc78db8474f7ebb2dabf52


箭头进度条代码实现

processBar.c

#include "processBar.h"
#include <string.h>
#include <unistd.h>const char *lable="|/-\\";void processbar()
{char bar[NUM];memset(bar,'\0',sizeof(bar));int len=strlen(lable);int cnt=0;while(cnt<=100){printf("[%-100s][%d%%][%c]\r",bar,cnt,lable[cnt%len]);fflush(stdout);bar[cnt++]=STYLE;if(cnt <=100) bar[cnt]='>';usleep(100000);}printf("\n");
}

processBar.h

#pragma once#include <stdio.h>#define NUM 102
#define STYLE '-'extern void processbar();

main.c

# include "processBar.h"
#include <unistd.h>int main()
{processbar();return 0;
}

实现效果:

c367f606a7fdc1c1eff71e0dafbac6fa

dc95e546ea847928c22b61ae746bf5de


多重进度条代码实现

processBar.c

#include "processBar.h"
#include <string.h>
#include <unistd.h>const char *lable="|/-\\";
char bar[NUM];void processbar(int rate)
{if(rate<0||rate>100) return;int len=strlen(lable);printf("[%-100s][%d%%][%c]\r",bar,rate,lable[rate%len]);fflush(stdout);bar[rate++]=BODY;if(rate <100) bar[rate]=RIGHT;
}void initbar()
{memset(bar,'\0',sizeof(bar));
}

processBar.h

#pragma once#include <stdio.h>#define NUM 102
#define TOP 100
#define BODY '='
#define RIGHT '>'extern void processbar(int rate);
extern void initbar();

main.c

# include "processBar.h"
#include <unistd.h>typedef void (*callback_t)(int);void downLoad(callback_t cd)
{int total = 1000; //1000MBint curr = 0; //0MBwhile(curr <= total){usleep(50000);int rate=curr*100/total;cd(rate);curr+=10;}printf("\n");
}int main()
{printf("download 1: \n");downLoad(processbar);initbar();printf("download 2: \n");downLoad(processbar);initbar();printf("download 3: \n");downLoad(processbar);initbar();printf("download 4: \n");downLoad(processbar);initbar();return 0;
}

实现效果:

9008f42d031aa83f7ab402b845b4914c


http://www.ppmy.cn/devtools/151329.html

相关文章

C++ union 联合(八股总结)

union&#xff08;联合体&#xff09;允许在同一内存位置上存储不同的数据类型&#xff0c;所有成员共享相同的内存空间。 内存布局 由于联合体的所有成员都共享同一块内存&#xff0c;因此联合体的大小是其最大成员的大小。联合体的实际大小取决于其最大成员的类型和对齐要求…

高性能计算服务器是指什么?

高性能计算服务器是一种具有高网络传输速度、快速极端和高速存储功能的服务器&#xff0c;高性能服务器还采用了先进的硬件技术和优化的软件配置&#xff0c;为企业和用户提供更快的响应时间和更高的并发处理能力&#xff0c;一般会用于处理大规模数据和复杂的计算任务当中。 本…

Spring Boot 下的Swagger 3.0 与 Swagger 2.0 的详细对比

先说结论&#xff1a; Swgger 3.0 与Swagger 2.0 区别很大&#xff0c;Swagger3.0用了最新的注释实现更强大的功能&#xff0c;同时使得代码更优雅。 就个人而言&#xff0c;如果新项目推荐使用Swgger 3.0&#xff0c;对于工具而言新的一定比旧的好&#xff1b;对接于旧项目原…

销售团队如何选择销售业绩统计表模板?

在销售团队中&#xff0c;统计和分析业绩是日常工作的重要部分。比如&#xff0c;通过统计表&#xff0c;我们可以看到上个月各销售员的成交额&#xff0c;了解哪些产品受欢迎&#xff0c;哪些区域市场潜力大。这不仅帮助我们回顾过往表现&#xff0c;还能为未来决策提供依据。…

链表 -- 反转链表,k个一组翻转链表,两两交换链表中结点

目录 反转链表 题目 ​编辑 分析 代码 k个一组翻转链表 题目 分析 代码 两两交换链表中的结点 题目 ​编辑 分析 代码 反转链表 题目 分析 反转过程: newhead作为遍历指针,最终停在尾结点上prev保存上一个结点,通过改变newhead和prev的连接来实现反转(核心)通过ne…

Kubernetes 部署 RabbitMQ 集群教程

本文介绍如何在 Kubernetes 中部署 RabbitMQ 集群&#xff0c;包含从命名空间创建到配置 NFS 存储的详细步骤。 参考文档&#xff1a; RabbitMQ 集群部署NFS StorageClass 创建 部署步骤 1. 创建命名空间 kubectl create ns rabbitmq2. 创建 RBAC 权限 创建文件 rabbitmq…

力扣 394. 字符串解码

&#x1f517; https://leetcode.cn/problems/decode-string 题目 对字符串中的 k[s] 解码为 s 重复 k 次 思路 碰到数字&#xff0c;开始进行递归 decode 展开&#xff0c;否则字符不解码针对于解码的部分&#xff0c;先明确 k 的数字是多少&#xff0c;再明确 [ ] 括号中…

精通Python (10)

一&#xff0c;基于tkinter模块的GUI GUI是图形用户界面的缩写&#xff0c;图形化的用户界面对使用过计算机的人来说应该都不陌生&#xff0c;在此也无需进行赘述。Python默认的GUI开发模块是tkinter&#xff08;在Python 3以前的版本中名为Tkinter&#xff09;&#xff0c;从这…