在使用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(())
}