【Linux详解】进度条实现 Linux下git 的远程上传

news2024/12/27 2:11:16

📃个人主页:island1314

🔥个人专栏:Linux—登神长阶

⛺️ 欢迎关注:👍点赞 👂🏽留言 😍收藏  💞 💞 💞

  


🚀前言

💢在实现进度条之前,我们先来了解一下换行和回车,以及缓冲区的概念,以便于我们来实现进度条,注:我们还需要用到上篇文章的知识:【Linux必备工具】自动化构建工具makefile的使用详解-CSDN博客

1. 回车与换行

我们在学C语言的时候,发现当我们在一行内容没有写完,然后要换到下一行的开始,我们要进行两个操作,

1:\n(换行)
让光标从第一行跳到第二行,但是光标只是垂直向下跳,并没有在第二行的开始。
2:\r(回车)
在第二行让光标跳到最开始的位置,这个操作就是回车。

那为啥我们在C语言的时候,怎么用\n来换行加回车?

因为这是我们在这个语言环境下我们将其简化,此时的\n就表示回车加换行。

测试字符

我们一共测试四种情况,

  1. \r和\n都存在
  2. \r和\n都不存在
  3. 只有\n
  4. 只有\r
🍎(1) \r和\n都存在

看下图可发现,我们在其中既有回车又有换行,所以其linux的命令行在我们执行程序下面。

🍌(2) \r和\n都不存在

看下图可发现:Linux命令行紧跟着打印的信息
因为我们结尾啥都没有,那光标就还在结尾,所以Linux命令行紧跟我们的打印信息

🍐(3) 只有\n

这里我们就省略演示了,毕竟这个现象和1相同,就是和我们的换行+回车,和我们平时用的一样,只不过我们的编译器将两步简化为一步了,我们只需要输入\n即可

🍇(4) 只有\r

现象:看不到打印的信息了。只能看到linux命令行
💢解释:因为我们\r,只有回车的效果,我们本来光标在文本行的最后一个字符旁边,但是我们识别到\r字符,所以,直接回车,光标来到了文本行的开始。这时linux的命令行就会从光标处开始,将我们的文本覆盖掉,我们就什们都看不到。

2. 缓冲区

2.1 缓冲区概念

💢缓冲区是计算机内存的一部分,用于暂时存储数据。它在数据传输过程中起到一个缓冲桥梁的作用,帮助协调数据传输的速度差异。缓冲区可以是磁盘缓存,网络传输中的数据缓存等。

2.2  缓冲区作用

缓冲区的作用非常广泛和重要,主要体现在以下几个方面:

 提升读写效率

  • 当进程要进行文件读写操作时,数据会首先存储在缓冲区中,而不是直接写入磁盘。缓冲区根据特定的刷新策略定期或在特定条件下将数据写入磁盘。这样可以减少磁盘的频繁读写动作,从而提升整体系统的效率。

 减少等待时间

  • 在没有缓冲区的情况下,每次文件读写操作都需要等待外设(如磁盘)就绪,这可能会导致显著的等待时间。缓冲区减少了这种等待时间,因为数据可以暂时存储在内存中,进程可以继续进行其他任务,而无需等待外设操作完成。

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

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

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

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

注:sleep的作用是按秒去休眠,头文件为<unisted.h>

然后当我们去除后面的 '\n' 则会出现什么了

缓存

💢实际上,printf 已经先执行了,只是这个 "Helo,World" 没有立马被显示出来罢了!

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

💢说明带有\n会马上刷新,那么不带的时候,那2s 代码就是存在我们的缓冲区, return 退出的时候,这个数据才显示出来,所以才看到了我们现在看到的现象 。

2.3 缓冲区刷新策略

缓冲区的刷新策略决定了何时将缓冲区中的数据真正写入到目标存储器,如磁盘或显示器。主要有以下几种策略:

a、无缓冲(Unbuffered)

数据一写入缓冲区就立即刷新写入目标设备。这种方式适合对时间敏感的操作,但可能导致系统资源的低效利用。

b、行缓冲(Line Buffered)

当缓冲区检测到换行符(\n)时,立即刷新写入目标设备。这种方式常用于终端显示器,以保证一行行的输出效果。例如,在终端或控制台输出时,行缓冲能确保即时显示用户输入的一行内容。

c、全缓冲(Fully Buffered)

只有当缓冲区满了时,才会将数据刷新写入目标设备。这种方式适合大量数据的写入操作,能提高整体的写入效率。例如,在将数据写入磁盘文件时,通常使用全缓冲策略。

d、特殊策略

  • 用户强制刷新
    用户可以显式调用刷新函数(如 fflush(FILE *stream)来强制刷新缓冲区内容。
  • 进程退出刷新
    当进程正常退出时,缓冲区会自动刷新,以确保所有已写入缓冲区但尚未写入目标设备的数据都被处理完毕。

如果我们想让上面的hello马上打印,就可以进行如下操作啦

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

int main()
{
   printf("Hello Linux");
   fflush(stdout); //立刻刷新,直接打印出结果
   sleep(2);
   return 0;
}

现在就会打印出1中(2)的那种结果啦

2.4 缓冲区存储位置

💢标准输入输出流(stdin、stdout、stderr)和文件流都是 FILE* 类型,它们在缓冲区管理中扮演了重要角色。当我们打开一个文件时,系统会返回一个 FILE* 类型的指针,文件的读写和关闭操作都需要该指针作为参数。

内部结构

💢struct FILE 封装了文件描述符(fd)、缓冲区以及缓冲区刷新策略。这使得文件操作变得高效和透明,开发者无需关心低级别的文件操作细节。

2.5 总结

💢缓冲区是提高系统数据读写效率的重要机制。理解和有效利用缓冲区及其刷新策略,可以显著提升程序性能和资源利用效率。


3. 进度条的实现

💢我们知道了上面两个知识点,\r将光标回到最开始就可以将其覆盖掉,所以我们利用这个特点可以写一个倒计时小程序,那我们先写一个10秒以内的倒计时小程序,这样方便更好来实现进度条

3.1 倒计时的实现

#include <stdio.h>
#include <unistd.h>
 
int main()
{
    int cnt=10;
    while(cnt--)//循环判断的条件
    {
        printf("倒计时:%-2d\r",cnt);//输出倒计时的数字,  %-2d把两位覆盖,\r刷新数据
        sleep(1);//间隔一秒
        fflush(stdout);//刷新缓冲区
 
    }
    printf("\n");//刷新缓冲区,换行               
    return 0;
}

3.2 进度条样式

  • 主体样式为两个中括号包裹,中间=>推进的方式呈现,比如:[======]
  • 主体右侧中括号位置保持不变,中间元素不断推进,比如:[= ]
  • 显示当前加载进度,用 [num%] 显示,num 随着进度条的不断推进而变化
  • 显示加载样式,可以利用一个旋转的字符,例如 [\] 的样式,顺时针不断旋转
    大约呈现状态为:[========>] [15%] [\]

3.3 采用多文件

文件存放在 processbar 目录中

  • process.h :函数声明
  • process.c :进度条逻辑
  • main.c :函数调用

3.4 代码如下:

🍉版本一:

process.h

#pragma once

//进度条函数
 void Progress(); 

process.c

#include "process.h"
#include <stdio.h>
#include <unistd.h>
#include <string.h>

#define NUM 101
#define STYLE '='

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

main.c

#include "process.h"

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


🥝版本二:

process.h

#pragma once

void FlushProcess(double total, double current);   

process.c

#include "process.h"
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

#define NUM 101
#define STYLE '='
#define POINT '.'
#define SPACE ' '

const int pnum = 6;

// 真实的进度条,一个根据具体的情况,比如下载的量来动态刷新进度
void FlushProcess(double total, double current)
{

	// 1. 更新当前进度的百分比
	double rate = (current / total) * 100;
	// printf("test: %.1lf%%\r",rate);
	// fflush(stdout);

    // 2. 更新进度条主体
	char bar[NUM]; // 这里 1% 更新一个等号
	memset(bar, '\0', sizeof(bar));
	int i = 0;//定义放到了外面,因为C99之前的for(int i; )不支持
	for (i = 0; i < (int)rate; i++)
	{
		bar[i] = STYLE;
	}

	// 3. 更新旋转光标或者其他风格
	static int num = 0;
	num++;
	num %= pnum;

	char points[pnum + 1];
	memset(points, '\0', sizeof(points));
	//直接用上面的i
	for (i = 0; i < pnum; i++)
	{
		if (i < num) points[i] = POINT;
		else  points[i] = SPACE;
	}

	// 4. test && printf
	printf("[%-100s][%.1lf%%]%s\r", bar, rate, points);
	fflush(stdout);
	// sleep(1);         
}

main.c

#include "process.h"
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>

const int pnum = 6;

typedef void(*flush_t)(double total, double current); // 刷新的函数指针类型
const int base = 100;
double total = 2048.0; // 2048MB
double once = 0.1;  // 0.5MB

// 进度条的调用方式
// 模拟下载行为
void download(flush_t f)
{
	double current = 0.0;
	while (current < total)
	{
		int r = rand() % base + 1;
		double speed = r * once;
		current += speed;
		if (current >= total) current = total;
		usleep(10000);

		// 更新除了本次新的下载量
		// 根据真实的应用场景,来进行动态刷新
	   //Process(total, current);
		f(total, current);

		// printf("test: %.1lf/%.1lf\r", current, total);
	   // fflush(stdout);
	}
	printf("\n");
}

int main()
{
	srand(time(NULL));
	download(FlushProcess);
	download(FlushProcess);
	download(FlushProcess);
	return 0;
}

进度条演示

4.  Linux上git的操作

4.1 上传

(1) 首先是在自己的gitee上新建远端仓库,然后复制仓库的地址

(2) git clone 

(3)git add [file name]

注:git add . 可以新增当前目录下所有未增文件

(4)git commit -m  " "    

-m选项代表的是本次的提交日志
" " 里面应该表明提交日志、描述改动的详细内容,务必培养这个好习惯。

(5)git push

4.2 git操作时遇到的问题

(1)为什么会提交失败

解决:

提示:Please tell me who you are.
翻译过来就是:请告诉我你是谁。
就是说这里git无法识别你是谁,你需要告诉 git 你的身份。
其实提示已经告诉了你的问题:

git config --global user.email "you@example.com"
git config --global user.name "Your Name"

我们直接用上面指令输入自己gitee上对应的邮箱名和名字即可

注:

💢💢git config命令的–global参数,用了这个参数,表示你这台机器上所有的Git仓库都会使用这个配置,当然也可以对某个仓库指定不同的用户名和Email地址。

而且我们也可以通过 git config -l 来查看配置信息

(2)push时出现的警告

warning: push.default is unset; its implicit value is changing in
Git 2.0 from 'matching' to 'simple'. To squelch this message
and maintain the current behavior after the default changes, use:

  git config --global push.default matching

To squelch this message and adopt the new behavior now, use:

  git config --global push.default simple

See 'git help config' and search for 'push.default' for further information.
(the 'simple' mode was introduced in Git 1.7.11. Use the similar mode
'current' instead of 'simple' if you sometimes use older versions of Git)

什么意思呢?简单来说:

git push其实有多种模式,不同的模式对应着不同的操作:今天我们简单看看上面提到的matching(匹配模式)和simple(简单模式):

  • matching:这是 Git 之前默认的模式
  • simple:这是一种适合初学者的模式,并且在 Git 2.0 之后默认就是这个模式

💢💢其具体区别我并不关心,什么分支匹配、什么推送拉取,先把 git 用起来,其他问题以后再说matching是之前默认的,正常使用肯定是没问题的;而simple是现在默认的,我看了一下,大概就是在推送时会进行一些检查,更适合新手。我在这里还是选用之前默认的matching模式

💢💢实际上这并不是一个报错,而是一个提示,你会发现在警告(warning)之后依然可以正常输入用户名和密码,因为他默认已经帮你选好了,就是simple模式,现在只是提醒你一下而已

解决方法:

  • 既然我们知道了这只是一个提示信息,而并非报错,那解决起来就很简单了
  • 根据 warning 的提示,选定一个默认的推送模式即可
# 执行此命令以选择旧版 git 的默认推送模式,并消除提示信息
git config --global push.default matching
# 执行此命令以选择旧版 git 的默认推送模式,并消除提示信息
git config --global push.default matching
  • 任意选择一个模式后,再进行git push指令的操作,就不会有警告了

4.3 git的小知识

(1)git status 可以查看git仓库状态

比如当我们新建了一个 test.c文件

若git add后则变成

 (2)git log 查看提交日志

(3) git pull

当我们 git push 出现下面的问题时

这个可能是由于 git 远端仓库 与本地仓库不一致的原因,因此我们可以用git pull 在git push 之前


📖总结

以上就是进度条实现 && Linux下git 的远程上传的全部内容啦!!!

💞 💞 💞那么本篇到此就结束,希望我的这篇博客可以给你提供有益的参考和启示,感谢大家支持!!!祝大家天天开心

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2041009.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

张飞硬件1~9电阻篇笔记

电阻有标定值和实际值&#xff0c;关于误差的问题&#xff1a; 精密的电流、电压采样可能会用到1%的精度。如果只是做限流用途的话&#xff0c;用5%就足够。 电阻功率&#xff1a;标定值、额定值、瞬态值&#xff1a; 标定值由封装所决定&#xff0c;例如5W额定值由电路中平…

结构开发笔记(三):solidworks软件(二):小试牛刀,绘制一个立方体

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/141122350 长沙红胖子Qt&#xff08;长沙创微智科&#xff09;博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV…

如果忘记了 Apple ID 密码,如何重设

“我忘记了我的 Apple ID 密码&#xff0c;如何恢复我的帐户&#xff1f;”为了方便用户&#xff0c;Apple 允许每个人使用唯一的 Apple ID 和密码激活设备并访问所有 Apple 服务。然而&#xff0c;实际上&#xff0c;手动选择某项并忘记它似乎很容易。例如&#xff0c;许多 Ap…

AI大模型零基础入门学习路线(非常详细)从入门到精通,看这篇就 够了

学习AI大模型从零基础入门到精通是一个循序渐进的过程&#xff0c;涉及到理论知识、编程技能和实践经验。下面是一份详细的指南&#xff0c;帮助你从头开始学习并逐步掌握AI大模型的构建与应用。 第一阶段&#xff08;10天&#xff09;&#xff1a;初阶应用 该阶段让大家对大…

北斗导航系统:助力保护生态环境的利器

近年来&#xff0c;随着科技的迅猛发展和生态危机的加剧&#xff0c;环保问题成了全球热点话题。而北斗导航系统&#xff0c;作为中国自主研发的全球卫星导航系统&#xff0c;不仅在军事和民用领域显示出了巨大潜力&#xff0c;也在应对生态保护挑战中发挥了重要作用。本篇文章…

ue5正确导入资源 content(内容),content只能有一个

把资源content下的东西&#xff0c;全部拷贝&#xff0c;放在项目的content下 content只能有一个

除毛除臭不够彻底?宠物空气净化器帮你解决

之前养猫的时候就想买一个空气净化器吸一吸空气的浮毛&#xff0c;尤其是夏天&#xff0c;因为夏天天气热流汗也会多&#xff0c;每次外出回家之后全身都是汗的时候想坐下来吹一下空调&#xff0c;但是一坐下去就会发现&#xff0c;沙发上全都是猫咪浮毛&#xff0c;而且还没开…

了解Android

Android 系统架构 从图中可以看出&#xff0c;整个Android操作系统分为五层。它们分别是&#xff1a; 内核层 Android系统是基于Linux内核的&#xff0c;这一层为Android设备的各种硬件提供了底层的驱动。硬件抽象层 该层为硬件厂商定义了一套标准的接口。这样可以在不影响上层…

Labelimg安装、使用及不显示标注、覆盖标签等问题

目录 1 安装 2 基本使用方法 3 显示已标记图片的标记 4 覆盖标签的问题 简单记录下Labelimg安装、使用以及在使用过程中遇到的几个问题的解决方法&#xff0c;以免忘记。 1 安装 这里是在Anaconda中搭建机器学习的环境&#xff0c;在Anaconda Prompt中激活虚拟环境后&…

C++ 之动手写 Reactor 服务器模型(二):服务器模型概述以及 Reactor 服务器 V1 版本实现

五种网络 IO 模型 就是下面五种&#xff1a; 要注意同步与异步、阻塞与非阻塞的辨析&#xff0c;常见误解就是认为&#xff1a;同步就是阻塞&#xff0c;异步就是非阻塞。 接下来分别给出例子来说明这五种 IO 模型。 基础知识 操作系统分为用户态和内核态。 一个网络数据输…

STM32低功耗与备用备份区域

STM的备份备用区域其实就是两个区块&#xff1a;BKP和RTC。低功耗则其实是STM32四种模式中的三种耗能很低的模式。 目录 一&#xff1a;备用区域 1.BKP 2.RTC 二&#xff1a;低功耗模式 1.睡眠模式&#xff1a; 2.停机模式&#xff1a; 3.待机模式&#xff1a; 一&…

AI绘画赏析:基于Stable Diffusion扩散模型

**Stable Diffusion**是2022年发布的深度学习文本到图像生成模型。它主要用于根据文本的描述产生详细图像&#xff0c;尽管它也可以应用于其他任务&#xff0c;如内补绘制、外补绘制&#xff0c;以及在提示词指导下产生图生图的翻译。它是一种潜在扩散模型&#xff0c;由慕尼黑…

【网络安全】15种常见网络攻击类型及防御措施_请列举至少三种常见的网络攻击类型,并说明如何通过防火墙、入侵检测系统等工具来

随着攻击者效率和复杂性的提高&#xff0c;网络犯罪每年都在急剧增加。网络攻击的发生有多种不同的原因和多种不同的方式。但是&#xff0c;一个共同点是网络犯罪分子会寻求利用组织的安全策略、实践或技术中的漏洞。 什么是网络攻击&#xff1f; 网络攻击是指攻击者出于盗窃…

防火墙入侵防御实验

一、实验目的及拓扑 实验目的&#xff1a;在防火墙上配置入侵防御&#xff08;跨站脚本攻击&#xff09;策略并在安全策略应用&#xff0c;通过虚拟机访问进行验证 二、基本配置 1、如图所示配置接口地址&#xff08;省略&#xff09; 2、配置区域接口 [FW1]dis zone loca…

文字翻译工具软件哪个好?这5款翻译神器好用到犯规

在日常工作和学习中&#xff0c;遇到需要翻译文字的情况再所难免。无论是查阅外文文献、与国际友人交流&#xff0c;还是理解不同语言的资讯&#xff0c;一款好用的文字翻译工具app都能大大提升我们的效率。 今天&#xff0c;我将给大家安利5款超实用的文字翻译工具app &#…

运维工程师必备技能:nc命令详解

&#x1f341;博主简介&#xff1a; &#x1f3c5;云计算领域优质创作者 &#x1f3c5;2022年CSDN新星计划python赛道第一名 ​ &#x1f3c5;2022年CSDN原力计划优质作者 ​ &#x1f3c5;阿里云ACE认证高级工程师 ​ &#x1f3c5;阿里云开发者社区专家博主 &#x1f48a;交流…

Java超市收银系统(七、商品修改和删除)

引言 当选择1时&#xff0c;显示 “输入商品编码&#xff1a;”&#xff0c;输入商品表中条码&#xff0c;若条码存在则删除商品表中的数据信息&#xff1b;若条码不存在&#xff0c;则显示 “你输入的编码不存在&#xff0c;请重新输入”。当选择2时&#xff0c;显示 “输入商…

【等保测评】Mysql测评中使用的命令汇总

一、身份鉴别 a) 应对登录的用户进行身份标识和鉴别&#xff0c;身份标识具有唯一性&#xff0c;身份鉴别信息具有复杂度要求并定期更换&#xff1b; mysql -uroot -p 查看登录是否需要输入口令鉴别用户身份 select user,host from mysql.user 查看是否存在相同账户…

OpenCV图像滤波(17)计算图像梯度函数Sobel()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 Sobel()函数用于计算图像的一阶、二阶、三阶或混合导数。它使用扩展的Sobel算子来执行这一任务。 在所有情况下&#xff0c;除了一种情况之外&am…

微信小程序 ==== 半屏打开小程序

目录 打开半屏小程序 调用流程 打开半屏小程序 半屏小程序环境判断 返回原小程序 使用限制 wx.openEmbeddedMiniProgram 功能描述 参数 wx.navigateBackMiniProgram 功能描述 示例代码 Object wx.getEnterOptionsSync() 功能描述 返回值 返回有效 referrerInfo…