【Linux】进度条与缓冲区

本文深入探讨了Linux系统中缓冲区的概念及其三种类型:全缓冲区、行缓冲区和无缓冲区,并介绍了它们的工作原理和刷新机制。此外,还提供了一个简单的实验来测量行缓冲区的实际大小。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Linux下缓冲区的刷新

直击主题:缓冲区

关于缓冲区,我们在C/C++编程时所了解到的就是系统提供的一个暂存区,暂时存放我们的输入和输出,是一块不太大的空间,至于具体为什么要有这块空间,当然是为了提高系统的效率;

当然,在这里就不得不提一个概念,就是标准库函数和系统调用之间的关系;

printf就是一个标准输出函数,标准库函数一般是对系统调用的封装,而printf即是对write系统调用的封装,不过在调用write之前,加入了一个缓冲区,即我们现在所说的这个缓冲区,而printf实际是向用户空间的IO缓冲写,在满足条件的情况下(条件下面会说)才会调用write系统调用,这样也就提高了内核的效率。

当然,这只是一般情况,还有其它的情况,对于系统调用和标准库函数的关系,下面我推荐一篇比较好的博客,毕竟我的水平还不够,但上面所说的内容已经可以满足本片博客的需求了;

推荐博客:

http://blog.youkuaiyun.com/skyflying2012/article/details/10044343


缓冲区的大小以及刷新方式

缓冲区的类型有三种:

标准I/O 提供了3 种类型的缓冲区。

1,全缓冲区:这种缓冲区要求填满整个缓冲区后才进行I/O 系统调用操作。对于磁盘文件通常使用全缓冲区访问。第一次执行I/O 操作时,ANSI 标准的文件管理函数通过调用malloc 函数获得需使用的缓冲区。默认大小为8192。

2,行缓冲区:在这种情况下,当在输入和输出中遇到换行符时,标准I/O 库执行I/O系统调用操作。当流涉及一个终端时(例如标准输入和标准输出),使用行缓冲区。因为标准I/O 库收集的每行的缓冲区长度是固定的,只要填满了缓冲区,即使还没有遇到换行符,也将执行I/O 系统调用操作。默认行缓冲区大小为128 字节。

3,无缓冲区:标准I/O 库不对字符进行缓存。如果用标准I/O 函数写若干字符到不带缓冲区的流中,则相当于用write 系统调用函数将这些字符写至相关联的打开文件。标准出错流stderr 通常是不带缓冲区的,这使得出错信息能够尽快地显示出来。

                                    -----参考红黑联盟

既然上面提到了行缓冲区的大小,我们就可以尝试写个小程序来测试一下我们的Linux的行缓冲区的大小;

思路:首先得知道缓冲区的刷新方式,即怎样打印内容;

printf是一个行缓冲函数,先写到缓冲区,满足条件后,才将缓冲区刷到对应文件中,刷缓冲区的条件如下:
1 行缓冲区填满
2 写入的字符中有‘\n’ 
3 调用fflush手动刷新缓冲区
4 调用scanf要从缓冲区中读取数据时,也会将缓冲区内的数据刷新
5 当然,程序结束也会刷新缓冲区

现在,我们知道了缓冲区的刷新方式,先不管其它的,先来想办法确定缓冲区的大小,刚好,刷新方式的第一条,把缓冲区填满,然后自动就刷新出来了,那只要我们把缓冲区写满,我们可以得到一个缓冲区的大小,二话不说,先来试试;

写下下面的代码:

这里写图片描述

分析: 这个代码的运行结果是个死循环,相信你已经注意到了,这是我目前为止想到的比较笨也是唯一知道的办法,其中加入了一句usleep函数(不知道usleep函数可以去man —_—|||),是因为没有加的话,找不到写满行缓冲区刷新时的分割,加入这个等待时间的话,他会有一定的停顿(时间自己把握),这样我们就可以Ctral+c结束程序,将打印出的那部分放在一个空文件里,然后看这个文件的大小就知道行缓冲区的大小了,结果如下:

这里写图片描述

复制到一个空的文件名为size的文件中,然后stat看文件的大小;

这里写图片描述

分析: 可以看到文件的大小是1025个字节;即1KB的行缓冲区;


进度条的实现:

前面说了行缓冲区,缓冲区的刷新,那么下面这个进度条的实现就是对上面知识的应用;

插入一点 \r 和 \n 的区别:

1.回车换行符,是2个符。一个回车,一个换行。\r仅仅是回车,\n是换行。一个是控制屏幕或者从键盘的Enter键输入。另一个是控制“打印机”!
2.回车 = 光标到达最左侧,换行 = 移到下一行。如果只回车,打印的东西会覆盖同行以前的内容,如果只换行,打印的东西会在下一行的先一个位置继续。
3.\r实际是回到行首。\n如果下一行已经有了一些内容的话它会在那些内容的后边.因为一般情况下下一行是没有数据的,很多时候\n也就成了\r\n作用一样。

注意上面加粗的那句话,进度条的实现利用到了这一点,还有fflush强制刷新缓冲区;

代码:

这里写图片描述

然后编辑一个主函数进行调用,我在这里简单的运用了make和makefile,对于make和Makefile会在后面的深入学习中进行总结;

结果展示:
这里写图片描述

### 实现或添加进度条功能的方法 在 Linux 环境下实现或使用进度条功能可以通过多种方法完成。以下是几种常见的技术手段及其具体实现: #### 方法一:通过 `cp` 和 `mv` 的增强工具 对于简单的文件操作,可以直接利用支持进度条的高级工具替代传统的 `cp` 和 `mv` 命令。这些工具提供了 `-g` 或 `--progress-bar` 参数用于显示进度条。 例如,使用 `rsync` 工具可以轻松实现带进度条的文件复制: ```bash rsync --progress source_file destination_path ``` 或者使用 `pv`(Pipe Viewer)命令作为管道的一部分来监控数据流的速度和总量: ```bash pv source_file > destination_path ``` 这种方法简单高效,适合日常文件管理任务[^2]。 --- #### 方法二:基于 `\r` 和 `fflush` 手动编写进度条逻辑 如果需要自定义进度条行为,则可以在程序中手动控制输出过程。核心原理是利用 `\r` 将光标返回至行首,并配合 `fflush(stdout)` 强制刷新缓冲区以即时更新屏幕内容。 下面是一个基本版本的 C 语言实现示例: ```c #include <stdio.h> #include <unistd.h> void progress_bar(int total, int current) { double percentage = (double)current / total * 100; printf("\rProgress: %.2f%% [%d/%d]", percentage, current, total); fflush(stdout); // 立即刷新输出缓冲区 } int main() { int total_steps = 100; for (int i = 0; i <= total_steps; ++i) { progress_bar(total_steps, i); usleep(100000); // 模拟耗时操作 } printf("\nCompleted!\n"); return 0; } ``` 此代码片段展示了如何动态打印百分比形式的进度条[^3][^4]。 更复杂的版本还可以引入 ASCII 图形化界面或其他库扩展视觉效果[^1]。 --- #### 方法三:借助第三方图形化组件 除了纯文本模式外,也可以考虑采用 GUI 库开发更加直观的应用程序。比如 GTK+ 提供了专门的 ProgressBar 控件,允许开发者创建交互性强的用户界面。 安装依赖包后可尝试如下 Python 脚本调用 GTK API 构建窗口展示进度变化情况: ```python import time from gi.repository import Gtk class ProgressWindow(Gtk.Window): def __init__(self): super().__init__(title="GTK Progress Bar Example") self.progressbar = Gtk.ProgressBar() self.add(self.progressbar) self.timeout_id = None self.connect("destroy", lambda w: Gtk.main_quit()) def start_progress(self): self.timeout_id = GObject.timeout_add(100, self.update_progress) def update_progress(self): new_value = self.progressbar.get_fraction() + 0.01 if new_value > 1: self.progressbar.set_fraction(0) else: self.progressbar.set_fraction(new_value) return True win = ProgressWindow() win.start_progress() win.show_all() Gtk.main() ``` 上述例子适用于桌面环境下的复杂场景需求。 --- ### 总结 无论是基础命令行工具还是定制化的脚本解决方案亦或是现代化跨平台框架集成方案都能满足不同层次的需求。选择合适的技术路径取决于实际应用场景以及个人偏好等因素。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值