30 个版本 (12 个稳定版)
1.3.1 | 2024年4月12日 |
---|---|
1.3.0 | 2023年10月26日 |
1.2.0 | 2023年5月17日 |
1.1.4 | 2023年1月6日 |
0.2.0 | 2018年11月26日 |
#91 in Rust 模式
19,603 个月下载量
用于 73 个 crate (10 直接使用)
145KB
2.5K SLoC
BufferedReader
是一个强大的 Read
er。
与 BufRead
特性一样,BufferedReader
特性具有一个内部缓冲区,该缓冲区直接暴露给用户。这种设计实现了两种性能优化。首先,使用内部缓冲区可以摊销系统调用。其次,暴露内部缓冲区允许用户就地处理数据,从而避免再次复制。
然而,BufRead
特性对于解析器有一个显著的限制:使用 BufRead
对象的用户无法控制缓冲区的大小。这对于能够方便地就地处理数据以及能够预览而不消耗数据是必要的。结果是,要么由 BufRead
对象的创建者处理大小——假设 BufRead
对象提供了这种机制——这是一种分层违规,或者如果内部缓冲区太小,解析器必须回退到缓冲区,这将消除 BufRead
抽象的大多数优点。通过允许用户控制内部缓冲区的大小,BufferedReader
特性解决了这一缺点。
BufferedReader
特性也提供了一些功能,特别是提供了一个泛型接口来处理一个 BufferedReader
对象的堆栈,这简化了同时使用多个解析器的操作。这在处理框架(例如,类似 HTTP 的分块传输编码)的一个解析器时非常有用,另一个解析器解码实际对象。当对象嵌套时也非常有用。
详细信息
因为 BufRead
特性没有为用户提供调整内部缓冲区大小的机制,因此解析器通常不能确定内部缓冲区是否足够大,以便能够处理所有数据。
使用标准的 BufRead
实现方式,即 BufReader
,创建者可以在创建时设置内部缓冲区的大小。不幸的是,这个机制很丑陋,并且并不总是足够。首先,解析器通常是创建者。因此,创建者需要了解所有解析器的实现细节,这使得实现细节变成了一个跨领域的关注点。其次,当处理动态大小的数据时,需要就地处理的数据的最大量可能事先未知,或者最大量可能比典型量大得多。这会导致缓冲区大小不当。
作为替代,使用但不创建一个 BufRead
对象的代码可以被改为流式传输数据,或者当内部缓冲区太小时代码回退到读取数据到本地缓冲区。这两种方法都增加了代码的复杂性,后者与 BufRead
的目标——减少不必要的复制——相悖。
BufferedReader
特性通过允许用户动态地(即,在读取时间,而不是打开时间)确保内部缓冲区有足够的数据来解决此问题。
控制内部缓冲区的大小对于直接支持预测性前瞻也是必不可少的。使用 BufRead
对象进行预测性前瞻之所以困难,是因为预测性前瞻是 /预测性的/,即如果解析器回溯,已读取的数据不得被消耗。使用 BufRead
对象,如果前瞻量大于内部缓冲区,这是不可能的。也就是说,如果前瞻数据量大于 BufRead
的内部缓冲区,解析器首先必须通过调用 BufRead::consume
()() 来消耗一些数据,以便检查更多数据。但是,如果解析器随后决定回溯,它没有方法将未使用的数据返回给 BufRead
对象。这迫使解析器管理一个已读取但未消费数据的缓冲区,这大大增加了代码的复杂性。
BufferedReader
特质通过两种方式简化了对BufferedReader
堆栈的操作。首先,BufferedReader
特质提供了访问底层BufferedReader
的泛型方法。因此,即使在处理特质对象时,仍然可以恢复底层的BufferedReader
。其次,BufferedReader
通过cookie提供了一个机制,将泛型状态与每个BufferedReader
相关联。尽管可以使用扩展BufferedReader
特质并封装现有BufferedReader
实现的自定义特质来实现此功能,但这种方法消除了大量容易出错且繁冗的代码。
依赖项
~6–260KB