#buffer #io #buffered

buffer-redux

std::io 中为缓冲 I/O 替换,并具有额外功能

3 个稳定版本

1.0.2 2024 年 8 月 5 日
1.0.1 2024 年 3 月 4 日
1.0.0 2023 年 3 月 18 日

#46算法

Download history 14695/week @ 2024-04-19 15426/week @ 2024-04-26 14962/week @ 2024-05-03 15699/week @ 2024-05-10 14123/week @ 2024-05-17 13527/week @ 2024-05-24 13877/week @ 2024-05-31 15325/week @ 2024-06-07 13676/week @ 2024-06-14 12029/week @ 2024-06-21 11594/week @ 2024-06-28 12925/week @ 2024-07-05 12532/week @ 2024-07-12 16081/week @ 2024-07-19 18805/week @ 2024-07-26 22996/week @ 2024-08-02

72,756 每月下载量
109 个crate中(5 直接)使用

MIT/Apache

100KB
1.5K SLoC

buffer-re(a)dux

Crates.io Crates.io Crates.io

未维护的 buf_redux 的分支。

std::io 中替换缓冲 I/O 类型。

这些替换保留了其stdlib对应者的方法名称/签名和实现的特质,使得替换就像交换类型的导入一样简单。

更多直接控制

所有替换类型都提供方法来

  • 增加缓冲区的容量
  • 获取可用字节数以及缓冲区的总容量
  • 消费包装器而不会丢失数据

BufReader 提供方法来

  • 通过 &-引用访问缓冲区而不执行 I/O
  • 强制无条件读取到缓冲区
  • 获取一个 Read 适配器,该适配器清空缓冲区然后直接从内部读取器中拉取
  • 将字节向下移动到缓冲区的开始,为更多读取腾出空间
  • 获取内部读取器和带有剩余数据的修剪缓冲区

BufWriterLineWriter 提供方法来

  • 刷新缓冲区并无条件地展开内部写入器。

更合理且可自定义的缓冲区行为

使用 policy 模块中的类型调整缓冲区的行为以适应您的特定用例

  • 通过实现 ReaderPolicy 特质或使用现有的实现(如 MinBuffered)来细化 BufReader 的行为,以确保缓冲区始终包含一定数量的字节(直到底层读取器为空)。

  • 通过实现 WriterPolicy 特质或使用现有的实现(如 FlushOn)来细化 BufWriter 的行为,当缓冲区中出现特定的字节时刷新(用于实现 LineWriter)。

使用方法

文档

Cargo.toml:

[dependencies]
buffer-redux = "0.2"

然后简单地交换要替换的类型导入

BufReader:

- use std::io::BufReader;
+ use buffer_redux::BufReader;

BufWriter:

- use std::io::BufWriter;
+ use buffer_redux::BufWriter;

LineWriter:

- use std::io::LineWriter;
+ use buffer_redux::LineWriter;

使用 MinBuffered

新的 policy::MinBuffered 读取策略可以确保 BufReader 的缓冲区中始终至少有特定数量的字节。这对于需要一定前瞻能力的解析应用非常有用。

use buffer_redux::BufReader;
use buffer_redux::policy::MinBuffered;
use std::io::{BufRead, Cursor};

let data = (1 .. 16).collect::<Vec<u8>>();

// normally you should use `BufReader::new()` or give a capacity of several KiB or more
let mut reader = BufReader::with_capacity(8, Cursor::new(data))
    // always at least 4 bytes in the buffer (or until the source is empty)
    .set_policy(MinBuffered(4)); // always at least 4 bytes in the buffer

// first buffer fill, same as `std::io::BufReader`
assert_eq!(reader.fill_buf().unwrap(), &[1, 2, 3, 4, 5, 6, 7, 8]);
reader.consume(3);

// enough data in the buffer, another read isn't done yet
assert_eq!(reader.fill_buf().unwrap(), &[4, 5, 6, 7, 8]);
reader.consume(4);

// `std::io::BufReader` would return `&[8]`
assert_eq!(reader.fill_buf().unwrap(), &[8, 9, 10, 11, 12, 13, 14, 15]);
reader.consume(5);

// no data left in the reader
assert_eq!(reader.fill_buf().unwrap(), &[13, 14, 15]);

注意:留出空间/环形缓冲区/slice-deque 功能

MinBuffered 这样的策略会读取到缓冲区并消耗其中的字节,而不会将其完全清空。在这种情况下,正常的缓冲区处理可能会耗尽可读/写空间,因为所有空闲空间都在缓冲区的头部。如果缓冲区中的数据量很小,可以在缓冲区类型上调用 .make_room() 来留出更多空间进行读取。MinBuffered 会自动执行此操作。

与此相反,使用 slice-deque 功能,您可以通过使用 ::new_ringbuf()::with_capacity_ringbuf() 构造函数而不是分别使用 ::new()with_capacity() 来为您缓冲区类型分配一个 环形缓冲区。使用环形缓冲区,从缓冲区中消耗/刷新字节会立即在缓冲区的末尾留出更多空间进行读取/写入。然而,这也有一些注意事项

  • 它仅在具有虚拟内存支持的目标平台上可用,即完整的操作系统,例如 Windows 和像 Linux、OS X、BSD 变体等 Unix 衍生平台。

  • 默认容量根据平台而异,自定义容量向上舍入为其最小尺寸的倍数,通常是平台的页面大小。由于一些历史原因,Windows 的最小尺寸相当大(64 KiB),因此对于某些用例,这可能不如正常缓冲区的默认容量(8 KiB)优化。

  • 由于虚拟内存技巧的本质,缓冲区分配的虚拟地址空间将是其实际容量的两倍。这意味着您的程序将 看起来 使用比使用相同容量的正常缓冲区更多的内存。在两种情况下,物理内存使用量都将相同,但如果您的应用程序中地址空间很宝贵(32 位目标),则这可能是一个问题。

这取决于您是否认为收益超过了成本。使用像 MinBuffered 这样的策略可能会显著提高性能。

许可

根据您的要求,许可如下:

任选其一。

贡献

除非您明确声明,否则任何有意提交以包含在您的工作中的贡献,根据 Apache-2.0 许可证定义,应按上述方式双许可,而无需任何额外条款或条件。

依赖关系

~110–495KB