6 个版本 (稳定)
1.2.2 | 2024年7月7日 |
---|---|
1.2.1 | 2024年2月22日 |
1.2.0 | 2024年1月4日 |
1.1.0 | 2023年12月23日 |
0.2.2 | 2023年8月20日 |
#146 in 异步
74KB
1K SLoC
get_chunk
关于
get_chunk
是一个用于创建文件迭代器或流(异步迭代器)的库,专门用于高效文件分块。主要任务,特别是从大文件中检索块数据的能力。
关键特性
- 文件分块: 将文件(包括大文件)分成无缝的块,每次“Next”迭代。
- 模式: 选择自动调整或根据百分比或字节计数手动设置块大小。
- 自动分块: 每次迭代“Next”动态确定最佳块大小,便于处理大型文件。
⚠️ 重要通知:
该算法在“Next”调用后调整块大小以优化性能,考虑可用RAM。然而,关键的是,这种调整仅在当前块发送并在下一个“Next”调用之前发生。
需要注意的是一种潜在的场景:假设一个块是15GB,最初有16GB的空闲RAM。如果在当前和下一个“Next”调用之间意外占用2GB RAM,则仍将处理当前15GB的块。这种情况存在风险,系统可能回收资源(导致io::error)或导致代码崩溃。
get_chunk
创建的迭代器不会在内存中存储整个文件,特别是对于大数据集。它们的目的是从文件中分块获取数据,保持效率。
关键点
- 文件保留有限: 为小文件创建迭代器可能会导致检索所有数据,OS相关。然而,这并不保证迭代器创建后文件持久性。
- 删除警告: 在迭代器或流迭代过程中删除文件将导致错误。这些结构不跟踪最后成功位置。
- 无法恢复文件: 在迭代过程中尝试恢复已删除的文件不受支持。这些结构不跟踪文件的原始状态。
迭代器版本
示例
use get_chunk::iterator::FileIter;
// Note: requires a `size_format` attribute.
use get_chunk::data_size_format::iec::IECUnit;
fn main() -> std::io::Result<()> {
let file_iter = FileIter::new("file.txt")?;
// or
// let file_iter = FileIter::try_from(File::open("file.txt")?)?;
// ...
for chunk in file_iter {
match chunk {
Ok(data) => {
// some calculations with chunk
//.....
println!("{}", IECUnit::auto(data.len() as f64));
}
Err(_) => break,
}
}
Ok(())
}
示例
use get_chunk::{
// Note: requires a `size_format` attribute.
data_size_format::iec::{IECSize, IECUnit},
iterator::FileIter,
ChunkSize,
};
fn main() -> std::io::Result<()> {
let file_iter = FileIter::new("file.txt")?
.include_available_swap()
.set_mode(ChunkSize::Bytes(40000))
.set_start_position_bytes(IECUnit::new(432.0, IECSize::Mebibyte).into());
Ok(())
}
流版本
示例
// Note: requires the `size_format` and `stream` attributes.
use get_chunk::data_size_format::iec::IECUnit;
use get_chunk::stream::{FileStream, StreamExt};
#[tokio::main]
async fn main() -> std::io::Result<()> {
let mut file_stream = FileStream::new("file.txt").await?;
// or
// let mut file_stream = FileStream::try_from_data(File::open("file.txt").await?)?;
// ...
while let Ok(chunk) = file_stream.try_next().await {
match chunk {
Some(chunk) => {
// some calculations with chunk
},
None => break,
}
}
Ok(())
}
工作原理
在ChunkSize
枚举中,calculate_chunk
函数根据各种参数确定最佳块大小。以下是计算大小的分解
变量prev
和now
分别表示上一次和当前的读取时间。
prev
定义:prev
表示上一次迭代中读取数据所花费的时间。
now
定义:now
表示当前迭代中读取数据片段所花费的时间。
-
自动模式
- 如果上一次读取时间(
prev
)大于零- 如果当前读取时间(
now
)也大于零- 如果
now
小于prev
,则使用decrease_chunk
方法减小块大小。 - 如果
now
大于或等于prev
,则使用increase_chunk
方法增加块大小。
- 如果
- 如果
now
为零或负数,则保持上一次的块大小(prev
)。
- 如果当前读取时间(
- 如果上一次读取时间是零或负数,则使用基于文件大小和可用RAM的默认块大小。
- 如果上一次读取时间(
-
百分比模式
- 使用
percentage_chunk
方法计算块大小为文件总大小的百分比。百分比限制在0.1%到100%之间。
- 使用
-
字节模式
- 使用
bytes_chunk
方法根据指定的字节数计算块大小。大小由文件大小和可用RAM限制。
- 使用
关键公式
- 增加块大小
(prev * (1.0 + ((now - prev) / prev).min(0.15))).min(ram_available * 0.85).min(f64::MAX)
- 减小块大小
(prev * (1.0 - ((prev - now) / prev).min(0.45))).min(ram_available * 0.85).min(f64::MAX)
- 默认块大小
(file_size * (0.1 / 100.0)).min(ram_available * 0.85).min(f64::MAX)
- 百分比块大小
(file_size * (percentage.min(100.0).max(0.1) / 100.0)).min(ram_available * 0.85)
- 字节块大小
(bytes as f64).min(file_size).min(ram_available * 0.85)
许可
依赖
~0.7–27MB
~393K SLoC