#chunk #iterator #async-io #filesize #read-file #file-io

get_chunk

支持自动或手动选择块大小的文件迭代器或流

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 异步


用于 ansi_parser_extended

MIT 许可证

74KB
1K SLoC

get_chunk

Crates.io Static Badge docs.rs Codecov

关于

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函数根据各种参数确定最佳块大小。以下是计算大小的分解

变量prevnow分别表示上一次和当前的读取时间。

prev

定义:prev表示上一次迭代中读取数据所花费的时间。

now

定义:now表示当前迭代中读取数据片段所花费的时间。

  1. 自动模式

    • 如果上一次读取时间(prev)大于零
      • 如果当前读取时间(now)也大于零
        • 如果now小于prev,则使用decrease_chunk方法减小块大小。
        • 如果now大于或等于prev,则使用increase_chunk方法增加块大小。
      • 如果now为零或负数,则保持上一次的块大小(prev)。
    • 如果上一次读取时间是零或负数,则使用基于文件大小和可用RAM的默认块大小。
  2. 百分比模式

    • 使用percentage_chunk方法计算块大小为文件总大小的百分比。百分比限制在0.1%到100%之间。
  3. 字节模式

    • 使用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)

许可

MIT许可

依赖

~0.7–27MB
~393K SLoC