【看表情包学Linux】(9) 缓冲区的概念 Git 三板斧 实现简易进度条_git缓冲区大小是什么(1)

最后的话

最近很多小伙伴找我要Linux学习资料,于是我翻箱倒柜,整理了一些优质资源,涵盖视频、电子书、PPT等共享给大家!

资料预览

给大家整理的视频资料:

给大家整理的电子书资料:

如果本文对你有帮助,欢迎点赞、收藏、转发给朋友,让我有持续创作的动力!

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以点击这里获取!

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

 看样子是先执行 B 再执行 A 了,but……

然而实际上,无论你加不加 \n,代码都是从上往下先运行的,即先执行 printf 再执行 sleep!

代码没有任何的循环判断跳转什么的操作,那一定是 从上到下按顺序执行的,要坚信自己!

这就是所谓的 “顺序结构”,也是我们的默认结构。

既然是从上到下按顺序执行,可是我们运行代码观察到的现象就是 sleep 先休眠 2s 然后打印啊。

 怎么肥事啊!!!

" 呵呵,printf 已经执行了,但是数据还没有刷新出来。"

**💡 真像:**实际上,printf 已经先执行了,只是这个 “Helo,World” 没有立马被显示出来罢了!

当我们 sleep 时也没有显示,当我们 sleep 完甚至到程序退出后,这个 “Helo,World” 才显示出来。

这个时候如果打印的消息如果没有立即被显示出来,

在 sleep 执行期间它最后显示出来证明了它的存在,

但是 sleep 2s 内它并没有显示出来,那么问题来了 —— 这个 “Helo,World” 在哪?

 难道有什么东西存着它吗?没错!有!这,就是  " 缓冲区 " !

0x01 缓冲区的理解

 什么是缓冲区?这个缓冲区在哪里?缓冲区其实说白了,就是一段内存空间。

既然是内存空间,那我们就能理解刚才举的例子里的 “Helo,World” 数据是放在了内存空间里。

只要在内存里就没有打印出来,所以我们 sleep 2s 时它一直在内存里 “躺平” 呢。

最后 return 退出的时候,这个数据才显示出来,所以才看到了我们现在看到的现象:

**缓冲区的理解:**就是一段内存空间。立马将内存中的空间显示出来 \rightarrow 刷新策略

我们今天不探讨什么策略,就往显示器打印这个点来说,我们只关注一种策略 —— 行刷新 !

所谓的行刷新,就是你要输出的一个行字符串当中,看它是不是一个完整行,

如果是一个完整行,就会立马刷新出来;如果不是,就不刷新,让它去缓冲区一边凉快去,

等缓冲区变满了或者程序退出了,再或者碰到换行服务,再把它一块送出去。

那么,如何证明你一个文本是完整的一行呢?

这也很简单,只要你打印的内容包含 \n,包含反斜杠 n 在内的之前的所有内容成为一行。

不是直接把数据刷到我们外设上, 还是把数据先放到缓冲区里,只不过因为你有 \n,

它就立马根据刷新策略,把内容给你刷新出来,仅此而已。

❓ 如果我不想用 \n,我就想让我的数据立马刷新出去(立马显示出来)呢?

这里就说来话长了,我们不得不说一下 stdin、stdout 和 stderr 的知识。

  一般一个程序默认在启动的时候会默认打开三个输入输出流:

#include <stdio.h>

extern FILE* stdin;
extern FILE* stdout;
extern FILE* stderr;

如何刷新呢?我们还可以通过 fflush() 去强制刷新:

#include <stdio.h>

int fflush(FILE* stream);

如果你仔细观察你会发现它的参数和我们 stdin、stdout 和 stderr 类型是一样的,都是 FILE*

" 实际上你们所有的 printf 底层打印的都是往 stdout 里丢的 "

在没有 \n 时,我们通过 fflush 让它打印完立马给我刷新:

🚩 运行结果如下:

Ⅱ. 实现一个简易 “进度条”

0x00 回车和换行的概念

 在实现简易 “进度条” 之前,我们还需要讲解一下回车和换行的概念。

**❓ 思考:**你认为回车和换行是一个概念吗?

  • 回车:将光标拨回到当前行的最开始(最左侧)
  • 换行:新起一行(并不影响光标的位置)

我们所理解的 “换行”  并不是这里的换行,想达到我们所理解的 “换行” 效果,

即新起一行并将光标拨回最开始位置,就需要:

回车 + 换行

 下面我们正式来谈一谈 “回车 + 换行” 的问题。

回车对应的就是 \r,而我们在 C语言中经常使用的 \n 其实就是 “回车 + 换行”。

0x01 先学会模拟 “倒计时”

为了写 “进度条”,我们先来模拟一下 “倒计时”

**💬 代码演示:**从 9 开始倒计时

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

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

  return 0;
}

🚩 运行结果演示:

0x02 开始实现简易进度条

我们想要实现的效果:

我们先创建一个空文件夹,并创建一个 process.c 文件:

$ mkdir process_bar
$ touch process.c

然后我们形成一个 Makefile 文件:

process:process.c
	gcc -o process process.c
.PHONY:clean
clean:
	rm -f process 

然后我们打开刚才创建的 process.c 文件,我们实现出 ‘#’ 的填充部分:

定义一个 process() 函数,用于实现进度条。我们假设 100 个单位,定义一个宏 TIMES 表示,然后创建 bar 数组存放,因为最后要存 \0 所以这里我们需要多预留一个位置给它,所以定义一个 TIMES+1 的宏,名曰 NUM。为了方便,我们索性使用 memset 将所有缓冲区空间设置为 \0。

然后开始我们的计数操作,创建一个 cnt 变量 while 它个 100 下,每次打印 bar 中的 1 个,然后用 # 填充 cnt 对应位置的 bar 元素。

然后让程序睡个一秒再继续走循环判断。

🚩 运行结果如下:

…… 额,这进度条未免有些沙雕哈,没关系,这是初始版嘛,很正常 ㅋㅋㅋㅋㅋ

emm,现在显然有两个问题亟待解决:

  • sleep 一秒,这是打印地是否有些太慢……
  • 这个进度条是否有些奇葩,哪有换行打的进度条雾草,太摩登了。

我们先来解决第一个问题,看看 usleep 函数,问问那个男人:

$ man 3 usleep

按照微秒为单位去休眠,我们 usleep(20000) ,能让它 2 秒内跑完。

20000\mu s = 20 ms = 0.02s

然后我们刚才还讲解缓冲区概念,的时候还介绍了 fflush()  和 \r,在这里就派上用场了。

和刚才的倒计时一样,这里换行的主要原因还是我们 printf 用了 \n,我们修改一下写的代码:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#define TIMES 100
#define NUM TIMES+1

void process() {
  char bar[NUM];
  memset(bar, '\0', sizeof(bar));  // 将所有缓冲区空间设置为\0

  int cnt = 0;
  while (cnt <= TIMES) {
    printf("[%s]\r", bar);  // 改成\r
    fflush(stdout);         // 将数据立马显示出来

    bar[cnt++] = '#';   // 填充#作为进度图例

    usleep(20000);      // 休眠0.02s  
  }
  
  printf("\n");    // 跑完再让他换个行
}

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

🚩 运行结果如下:

不错,有个进度条的样子了。但好像没有给进度条预留一块空间啊,

现在的进度条是带着 [ ] 直接往后怼的,我们可以给 [ ] 预留 100 个 字符空间:

printf("[%100s]\r", bar);

我们来看看效果如何,3,2,1 笑:

哈哈哈哈哈哈,太沙雕了,虽然给 [ ] 预留空间了,但是是从右往左反过来打的。

  从右往左?阿拉伯兄弟直呼内行!

为什么会这样呢?因为 C 语言默认的对齐方式是右对齐的,如果想让它左对齐,就要加 -

printf("[%-100s]\r", bar);

这下就没有问题了:

下面我们来加上 “百分比”

百分比不就是我们定义的 cnt 变量么?我们打印出来就行:

printf("[%-100s] [%d %%]\r", bar, cnt);

最后,我们再实现一下 “不断旋转的光标”,就大功告成了。

想做到不断旋转的视觉效果,通过   | / - \ 这四个符号不断变化即可。

由于 \ 需要用转义才能表示,所以需要 ****\ ,我们把它们存到变量中。

打印时,访问我们定义的变量即可,这里将  cnt % 4 就可以按顺序循环访问这四个字符了。

/* 不断旋转的光标:   | / - \   */


为了做好运维面试路上的助攻手,特整理了上百道 **【运维技术栈面试题集锦】** ,让你面试不慌心不跳,高薪offer怀里抱!

这次整理的面试题,**小到shell、MySQL,大到K8s等云原生技术栈,不仅适合运维新人入行面试需要,还适用于想提升进阶跳槽加薪的运维朋友。**

![](https://img-blog.csdnimg.cn/img_convert/7e1917a73f3a94804de4b2717ccfdcb5.png)

本份面试集锦涵盖了

*   **174 道运维工程师面试题**
*   **128道k8s面试题**
*   **108道shell脚本面试题**
*   **200道Linux面试题**
*   **51道docker面试题**
*   **35道Jenkis面试题**
*   **78道MongoDB面试题**
*   **17道ansible面试题**
*   **60道dubbo面试题**
*   **53道kafka面试**
*   **18道mysql面试题**
*   **40道nginx面试题**
*   **77道redis面试题**
*   **28道zookeeper**

**总计 1000+ 道面试题, 内容 又全含金量又高**

*   **174道运维工程师面试题**

> 1、什么是运维?

> 2、在工作中,运维人员经常需要跟运营人员打交道,请问运营人员是做什么工作的?

> 3、现在给你三百台服务器,你怎么对他们进行管理?

> 4、简述raid0 raid1raid5二种工作模式的工作原理及特点

> 5、LVS、Nginx、HAproxy有什么区别?工作中你怎么选择?

> 6、Squid、Varinsh和Nginx有什么区别,工作中你怎么选择?

> 7、Tomcat和Resin有什么区别,工作中你怎么选择?

> 8、什么是中间件?什么是jdk?

> 9、讲述一下Tomcat8005、8009、8080三个端口的含义?

> 10、什么叫CDN?

> 11、什么叫网站灰度发布?

> 12、简述DNS进行域名解析的过程?

> 13、RabbitMQ是什么东西?

> 14、讲一下Keepalived的工作原理?

> 15、讲述一下LVS三种模式的工作过程?

> 16、mysql的innodb如何定位锁问题,mysql如何减少主从复制延迟?

> 17、如何重置mysql root密码?

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以点击这里获取!](https://bbs.csdn.net/topics/618542503)**

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

?

> 8、什么是中间件?什么是jdk?

> 9、讲述一下Tomcat8005、8009、8080三个端口的含义?

> 10、什么叫CDN?

> 11、什么叫网站灰度发布?

> 12、简述DNS进行域名解析的过程?

> 13、RabbitMQ是什么东西?

> 14、讲一下Keepalived的工作原理?

> 15、讲述一下LVS三种模式的工作过程?

> 16、mysql的innodb如何定位锁问题,mysql如何减少主从复制延迟?

> 17、如何重置mysql root密码?

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以点击这里获取!](https://bbs.csdn.net/topics/618542503)**

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值