rust 异步zip解压缩

发布于:2024-04-08 ⋅ 阅读:(142) ⋅ 点赞:(0)

在使用actix-web框架的时候,如果使用zip解压任务将会占用一个工作线程,因为zip库是同步阻塞的,想用异步非阻塞需要用另一个库,下面列出同步解压,跟异步解压的两个方法实现,异步解压不会占用工作线程。

阻塞解压

依赖库

zip = "0.6.6"

rust代码

pub fn unzip<P: AsRef<std::path::Path>>(
    file_path: P,
    unzip_path: P,
) -> Result<(), std::io::Error> {
    let file_path = file_path.as_ref();
    let unzip_path = unzip_path.as_ref();
    let unzip_path = std::path::Path::new(unzip_path);
    if unzip_path.exists() {
        std::fs::remove_dir_all(unzip_path)?;
    } else {
        std::fs::create_dir_all(unzip_path)?;
    }
    let file = std::fs::File::open(file_path)?;
    let mut archive = zip::ZipArchive::new(file)?;
    for index in 0..archive.len() {
        let mut file = archive.by_index(index)?;
        let file_name = file.mangled_name();
        let outpath = unzip_path.join(file_name);
        if file.is_dir() {
            std::fs::create_dir_all(&outpath)?;
        } else {
            if let Some(p) = outpath.parent() {
                if !p.exists() {
                    std::fs::create_dir_all(p)?;
                }
            }
            let mut outfile = std::fs::File::create(&outpath)?;
            std::io::copy(&mut file, &mut outfile)?;
        }
    }
    return Ok(());
}

异步解压

依赖库

async_zip = { version = "0.0.17", features = ["tokio", "tokio-fs", "deflate"] }
futures-lite = "2.3.0"
tokio = { version = "1.35.1", features = ["macros"] }
tokio-util = "0.7.10"

rust代码

use async_zip::base::read::seek::ZipFileReader;
use async_zip::base::write::ZipFileWriter;
use async_zip::ZipEntryBuilder;
use tokio::fs::OpenOptions;
use tokio_util::compat::{TokioAsyncReadCompatExt, TokioAsyncWriteCompatExt};

pub async fn unzip_async<P: AsRef<std::path::Path>>(
    file_path: P,
    unzip_path: P,
) -> Result<(), ApiError> {
    let unzip_path = unzip_path.as_ref();
    if unzip_path.exists() {
        std::fs::remove_dir_all(unzip_path)?;
    } else {
        std::fs::create_dir_all(unzip_path)?;
    }
    let file = tokio::fs::File::open(file_path.as_ref()).await?;
    let reader = tokio::io::BufReader::new(file);
    let mut zip = ZipFileReader::with_tokio(reader)
        .await
        .map_err(ApiError::from)?;
    for index in 0..zip.file().entries().len() {
        let entry = zip
            .file()
            .entries()
            .get(index)
            .ok_or(ApiError::msg("zip entry not found"))?;
        let raw = entry.filename().as_bytes();
        let mut file_name = &String::from_utf8_lossy(raw).to_string(); //必需转换为utf8,不能使用自带的,会乱码
        let outpath = unzip_path.join(file_name);
        if file_name.ends_with("/") {
            tokio::fs::create_dir_all(&outpath).await?;
        } else {
            if let Some(p) = outpath.parent() {
                if !p.exists() {
                    tokio::fs::create_dir_all(p).await?;
                }
            }
            let mut entry_reader = zip
                .reader_without_entry(index)
                .await
                .map_err(ApiError::from)?;
            let mut writer = OpenOptions::new()
                .write(true)
                .create_new(true)
                .open(&outpath)
                .await
                .map_err(ApiError::from)?;
            futures_lite::io::copy(&mut entry_reader, &mut writer.compat_write()).await?;
        }
    }
    Ok(())
}

网站公告

今日签到

点亮在社区的每一天
去签到