Linux基础开发工具(编写一个简易进度条)

目录

1.回车换行

2.缓冲区问题

[那么在我们休眠3秒期间hello world!在哪里?](#那么在我们休眠3秒期间hello world!在哪里?)

[程序会默认打开三个输入输出流 FILE*类型](#程序会默认打开三个输入输出流 FILE*类型)

3.倒计时程序

1.初版 2.第二版 3.终版

理解显示

4.进度条

想实现的进度条

1.第一版

1.初步 2.process.c

2.第二版


继上节的make/Makefile篇,我们这节来完成一个命令行版的简易的进度条

1.回车换行

回车 \r 换行 \n

回车换行 \r\n

一般\n被自动解析成\r\n

  • 回车 \r:将光标移动到当前行的开头(水平移动)。

  • 换行 \n:将光标移动到下一行的同一列(垂直移动)。

2.缓冲区问题

今天先简单讲一下缓冲区,先理解为一段内存块

myproc.c

复制代码
1 #include<stdio.h>
2 #include<unistd.h>                                                                                
3 
4 int main()
5 {   
6     printf("hello world!\n");
7     sleep(3);
8     return 0;
9 }

sleep

先等3秒之后退出。

然后把myproc.c的\n去掉

复制代码
1 #include<stdio.h>
2 #include<unistd.h>
3 
4 int main()
5 {
6     //printf("hello world!\n");                                                                   
7     printf("hello world!");
8     sleep(3);
9     return 0;
10 }

发现是先休眠3秒在打印hello world!

不要以为第二个是先执行sleep再printf。

程序执行永远是从前往后执行的,先执行printf再执行printf

一定把printf执行完了!但是显示器上没有显示,

那么在我们休眠3秒期间hello world!在哪里?

在缓冲区里面

我们往显示器上打印称为行刷新

如果没有\n就不会刷新**,那么为什么最终还是有打印出来呢?**

是因为程序退出,会自动刷新缓冲区!
小知识点

fprintf

复制代码
1 #include<stdio.h>
2 #include<unistd.h>
3 
4 int main()
5 {
6     //printf("hello world!\n");
7     fprintf(stdout,"hello world!\n");                                                             
8     sleep(3);
9     return 0;
10 } 

这里两个一样

如果想让它立马刷新呢?

可以使用fflush

复制代码
1 #include<stdio.h>
2 #include<unistd.h>
3 
4 int main()
5 {
6     printf("hello world!");
7     fflush(stdout);                                                                               
8     //printf("hello world!\n");
9     //fprintf(stdout,"hello world!\n");
10     sleep(3);
11     return 0;
12 }  

程序会默认打开三个输入输出流 FILE*类型

复制代码
extern FILE *stdin;    键盘
extern FILE *stdout;   显示器
extern FILE *stderr;   显示器

printf实际上是往stdout上打

3.倒计时程序

1.初版

myproc.c

复制代码
1 #include<stdio.h>
2 #include<unistd.h>
3 
4 int main()
5 {
6     int i = 9;
7     while (i >= 0)
8     {
9 
10         printf("%d\n", i);
11         i--;
12     }
13     return 0;
14 }

我们想要让9876543210在同一个位置打印

2.第二版

myproc.c

复制代码
1 #include<stdio.h>
2 #include<unistd.h>
3 int main()
4 {
5     int i = 9;
6     while (i >= 0)
7     {
8 
9         printf("%d\r", i);                                                                        
10         i--;
11         sleep(1);
12     }
13     return 0;
14 }

\r 是回车符(Carriage Return),其作用是将光标移动到当前行的开头,不换行

结果我们发现,因为没有\n没有刷新缓冲区。

所以对应的信息没有显示出来

3.终版

myproc.c

复制代码
1 #include<stdio.h>                                                                                 
2 #include<unistd.h>
3 int main()
4 {
5     int i = 9;
6     while (i >= 0)
7     {
8     
9         printf("%d\r", i);
10         fflush(stdout);
11         i--;
12         sleep(1);
13     }   
14     printf("\n");
15     return 0;
16 }

显示效果成功(因为是动态不好演示,可以自行尝试)

理解显示

但如果这里给10

复制代码
1 #include<stdio.h>
2 #include<unistd.h>
3 
4 int main()
5 {
6     int i = 10;                                                                                   
7     while (i >= 0)
8     {
9         
10         printf("%d\r", i);
11         fflush(stdout);
12         i--;
13         sleep(1);
14     }
15     printf("\n");
16     return 0;
17 }

会发现是两位,并不会从两位变成一位的

显示器只认字符!---字符设备

因此改成

myproc.c

复制代码
1 #include<stdio.h>
2 #include<unistd.h>
3 
4 int main()
5 {
6     int i = 10;
7     while (i >= 0)
8     {
9 
10         printf("%-2d\r", i);                                                                      
11         fflush(stdout);
12         i--;
13         sleep(1);
14     }
15     printf("\n");
16     return 0;
17 }

第十行,改成 printf("%-2d\r", i);

2d两个字符,"-"向左对齐。

从而实现成功

4.进度条

接下来,我们就开始进度条的操作

想实现的进度条

## \]\[53%\]\[/

每过一个百分点多一个#号,53%那个会动,/处会旋转。
ctrl+ww,可以使光标移动到另一端 切换

1.第一版

前置准备

复制代码
[user1@iZ5waahoxw3q2bZ 26-4-15.2]$ mkdir processbar
[user1@iZ5waahoxw3q2bZ 26-4-15.2]$ cd processbar

[user1@iZ5waahoxw3q2bZ processbar]$ touch process.h
[user1@iZ5waahoxw3q2bZ processbar]$ touch process.c
[user1@iZ5waahoxw3q2bZ processbar]$ touch main.c
[user1@iZ5waahoxw3q2bZ processbar]$ ll
total 0
-rw-rw-r-- 1 user1 user1 0 Apr 15 22:16 main.c
-rw-rw-r-- 1 user1 user1 0 Apr 15 22:16 process.c
-rw-rw-r-- 1 user1 user1 0 Apr 15 22:16 process.h

Makefile

复制代码
1 SRC=$(wildcard *.c)
2 OBJ=$(SRC:.c=.o)
3 BIN=processbar
4 
5 $(BIN):$(OBJ)
6     gcc -o $@ $^
7 %.o:%.c
8     gcc -c $<
9 
10 .PHONY:
11 clean:
12     rm -f $(OBJ) $(BIN) 

1.初步

process.h

复制代码
1 #pragma once                                   
2                                                
3 #include<stdio.h>                              
4                                                
5 void process_v1();

process.c

复制代码
1 #include"process.h"
2 
3 void process_v1()
4 {
5     printf("hello world!\n");
6 }  

main.c

复制代码
1 #include"process.h"
2 
3 int main()
4 {
5     process_v1();
6     return 0;
7 }

make

复制代码
[user1@iZ5waahoxw3q2bZ processbar]$ make
gcc -c process.c
gcc -o processbar main.o process.o
[user1@iZ5waahoxw3q2bZ processbar]$ ll
total 36
-rw-rw-r-- 1 user1 user1   68 Apr 15 22:33 main.c
-rw-rw-r-- 1 user1 user1 1368 Apr 15 22:36 main.o
-rw-rw-r-- 1 user1 user1  137 Apr 15 22:21 Makefile
-rwxrwxr-x 1 user1 user1 8512 Apr 15 22:38 processbar
-rw-rw-r-- 1 user1 user1   73 Apr 15 22:38 process.c
-rw-rw-r-- 1 user1 user1  211 Apr 15 22:36 process.h
-rw-rw-r-- 1 user1 user1 1504 Apr 15 22:38 process.o
[user1@iZ5waahoxw3q2bZ processbar]$ ./processbar
hello world!

2.process.c

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

#define NUM 101
#define STYLE '#'

void process_v1()
{
    char buffer[NUM];
    memset(buffer, 0, sizeof(buffer));
    const char* lable = "|/-\\";
    int len = strlen(lable);

    int cnt = 0;
    while (cnt <= 100)
    {
        printf("[%-100s][%d%%][%c]\r", buffer, cnt, lable[cnt % len]);
        fflush(stdout);
        buffer[cnt] = STYLE;
        cnt++;
        usleep(50000);  // 50ms
    }
    printf("\n");
}

2.第二版

process.c

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

#define BAR_WIDTH 50

void FlushProcess(double total, double current)
{
    double percent = (current / total) * 100;
    int bar_len = (int)((current / total) * BAR_WIDTH);
    // 保证不超出范围
    if (bar_len > BAR_WIDTH) bar_len = BAR_WIDTH;

    printf("\r[");
    for (int i = 0; i < BAR_WIDTH; ++i) {
        if (i < bar_len)
            printf("#");
        else
            printf(" ");
    }
    printf("] %.2lf%%", percent);
    fflush(stdout);
}

typedef void (*callback_t)(double total, double current);

double total = 1024.0;
double speed = 1.0;

void DownLoad(callback_t cb)
{
    double current = 0;
    while (current <= total) {
        cb(total, current);
        usleep(3000);      // 模拟下载数据
        current += speed;
    }
    printf("\ndownload %.2lfMB Done\n", current);
}

void UpLoad(callback_t cb)
{
    double current = 0;
    while (current <= total) {
        cb(total, current);
        usleep(3000);      // 模拟上传数据
        current += speed;
    }
    printf("\nupload %.2lfMB Done\n", current);
}

int main()
{
    DownLoad(FlushProcess);
    UpLoad(FlushProcess);
    return 0;
}

今天我们的学习就到此结束,期待我们下次再见!!!

相关推荐
Hello.Reader2 小时前
算法是什么
linux·运维·算法
cui_ruicheng2 小时前
Linux IO入门(二):重定向与缓冲区机制
linux·运维·服务器
有谁看见我的剑了?2 小时前
Linux 内核参数优化
linux·网络·php
Harvy_没救了2 小时前
Ansible 学习指南
linux·运维·服务器·ansible
有谁看见我的剑了?2 小时前
Linux 内存巨页与透明巨页学习
java·linux·学习
jinyishu_2 小时前
链表经典算法题(2)
c语言·数据结构·链表
blog.pytool.com2 小时前
Ubuntu + VSCODE +aarch64 +qt +qmake +clangd
linux·qt·ubuntu
学Linux的语莫2 小时前
Linux环境中anaconda 的安装与环境配置
linux·运维·服务器
回忆2012初秋2 小时前
C# 射线算法:判断GPS点是否在车辆工作区域内
linux·算法·c#