rust?zip異步壓縮與解壓的代碼詳解
在使用actix-web框架的時(shí)候,如果使用zip解壓任務(wù)將會(huì)占用一個(gè)工作線程,因?yàn)閦ip庫(kù)是同步阻塞的,想用異步非阻塞需要用另一個(gè)庫(kù),下面列出同步解壓,跟異步解壓的兩個(gè)方法實(shí)現(xiàn),異步解壓不會(huì)占用工作線程。注意:debug模式下rust異步壓縮會(huì)很慢,打包成release之后就非??炝?。
壓縮
依賴
tokio = { version = "1.35.1", features = ["macros"] }
tokio-util = "0.7.10"
async_zip = { version = "0.0.17", features = ["tokio", "tokio-fs", "deflate"] }
futures-lite = "2.3.0"
anyhow = "1.0.44"rust代碼
use anyhow::anyhow;
use async_zip::tokio::read::seek::ZipFileReader;
use async_zip::tokio::write::ZipFileWriter;
use async_zip::{Compression, DeflateOption, ZipEntryBuilder};
use futures_lite::AsyncWriteExt;
use std::path::{Path, PathBuf};
use tokio::fs::File;
use tokio::fs::{create_dir_all, OpenOptions};
use tokio::fs::{read_dir, remove_dir_all};
use tokio::io::{AsyncBufReadExt, AsyncReadExt, BufReader};
use tokio_util::compat::TokioAsyncWriteCompatExt;
use tokio_util::compat::{FuturesAsyncWriteCompatExt, TokioAsyncReadCompatExt};
//讀取文件夾文件
async fn dirs(dir: PathBuf) -> Result<Vec<PathBuf>, anyhow::Error> {
let mut dirs = vec![dir];
let mut files = vec![];
while !dirs.is_empty() {
let mut dir_iter = read_dir(dirs.remove(0)).await?;
while let Some(entry) = dir_iter.next_entry().await? {
let entry_path_buf = entry.path();
if entry_path_buf.is_dir() {
dirs.push(entry_path_buf);
} else {
files.push(entry_path_buf);
}
}
}
Ok(files)
}
//壓縮單個(gè)文件
async fn zip_entry(
input_path: &Path,
file_name: &str,
zip_writer: &mut ZipFileWriter<File>,
) -> Result<(), anyhow::Error> {
let mut input_file = File::open(input_path).await?;
let builder = ZipEntryBuilder::new(file_name.into(), Compression::Deflate)
.deflate_option(DeflateOption::Normal);
let mut entry_writer = zip_writer.write_entry_stream(builder).await?;
futures_lite::io::copy(&mut input_file.compat(), &mut entry_writer).await?;
entry_writer.close().await?;
return Ok(());
}
//壓縮
pub async fn zip(input_path: &Path, out_path: &Path) -> Result<(), anyhow::Error> {
let file = File::create(out_path).await?;
let mut writer = ZipFileWriter::with_tokio(file);
let input_dir_str = input_path
.as_os_str()
.to_str()
.ok_or(anyhow!("Input path not valid UTF-8."))?;
if input_path.is_file() {
let file_name = input_path
.file_name()
.ok_or(anyhow!("File name not found.".to_string()))?
.to_string_lossy();
zip_entry(input_path, &file_name, &mut writer).await?;
} else {
let entries = dirs(input_path.into()).await?;
for entry_path_buf in entries {
let entry_path = entry_path_buf.as_path();
let entry_str = entry_path
.as_os_str()
.to_str()
.ok_or(anyhow!("Directory file path not valid UTF-8."))?;
let file_name = &entry_str[(input_dir_str.len() + 1)..];
zip_entry(entry_path, file_name, &mut writer).await?;
}
}
writer.close().await?;
Ok(())
}
//解壓
pub async fn unzip<T: AsRef<Path>>(path: T, out_path: T) -> Result<(), anyhow::Error> {
let out_path = out_path.as_ref();
if out_path.exists() {
remove_dir_all(out_path).await?;
} else {
create_dir_all(out_path).await?;
}
let path = path.as_ref();
let file = File::open(path).await?;
let reader = BufReader::new(file);
let mut zip = ZipFileReader::with_tokio(reader).await?;
for index in 0..zip.file().entries().len() {
let entry = zip
.file()
.entries()
.get(index)
.ok_or(anyhow!("zip entry not found".to_string()))?;
let raw = entry.filename().as_bytes();
let mut file_name = &String::from_utf8_lossy(raw).to_string(); //必需轉(zhuǎn)換為utf8,否則有亂碼
let zip_path = out_path.join(file_name);
if file_name.ends_with("/") {
create_dir_all(&zip_path).await?;
continue;
}
if let Some(p) = zip_path.parent() {
if !p.exists() {
create_dir_all(p).await?;
}
}
let mut entry_reader = zip.reader_without_entry(index).await?;
let mut writer = OpenOptions::new()
.write(true)
.create_new(true)
.open(&zip_path)
.await?;
futures_lite::io::copy(&mut entry_reader, &mut writer.compat_write()).await?;
}
Ok(())
}測(cè)試
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_zip() -> Result<(), anyhow::Error> {
let path = Path::new("file/tmp/test");
zip(path, Path::new("file/tmp/out.zip")).await?;
Ok(())
}
#[tokio::test]
async fn test_unzip() -> Result<(), anyhow::Error> {
let path = Path::new("file/tmp/a/out.zip");
unzip(path, Path::new("file/tmp")).await?;
Ok(())
}
}到此這篇關(guān)于rust zip異步壓縮與解壓的文章就介紹到這了,更多相關(guān)rust zip解壓內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Rust中的Box<T>之堆上的數(shù)據(jù)與遞歸類型詳解
本文介紹了Rust中的Box<T>類型,包括其在堆與棧之間的內(nèi)存分配,性能優(yōu)勢(shì),以及如何利用Box<T>來(lái)實(shí)現(xiàn)遞歸類型和處理大小未知類型,通過(guò)Box<T>,Rust程序員可以更靈活地管理內(nèi)存,避免編譯時(shí)大小不確定的問(wèn)題,并提高代碼的效率和靈活性2025-02-02
Rust并發(fā)編程之使用消息傳遞進(jìn)行線程間數(shù)據(jù)共享方式
文章介紹了Rust中的通道(channel)概念,包括通道的基本概念、創(chuàng)建并使用通道、通道與所有權(quán)、發(fā)送多個(gè)消息以及多發(fā)送端,通道提供了一種線程間安全的通信機(jī)制,通過(guò)所有權(quán)規(guī)則確保數(shù)據(jù)安全,并且支持多生產(chǎn)者單消費(fèi)者架構(gòu)2025-02-02
使用cargo install安裝Rust二進(jìn)制工具過(guò)程
cargoinstall是一個(gè)用于安裝包含可執(zhí)行目標(biāo)的Rust包的命令行工具,類似于系統(tǒng)軟件包管理器,但它為Rust開(kāi)發(fā)者提供了一種簡(jiǎn)潔的方式來(lái)安裝和管理命令行工具,安裝后,二進(jìn)制文件會(huì)存儲(chǔ)在$HOME/.cargo/bin目錄中,需要將該目錄添加到$PATH環(huán)境變量中才能在命令行中直接運(yùn)行2025-02-02
rust的nutyp驗(yàn)證和validator驗(yàn)證數(shù)據(jù)的方法示例詳解
本文介紹了在Rust語(yǔ)言中,如何使用nuType和validator兩種工具來(lái)對(duì)Cargo.toml和modules.rs文件進(jìn)行驗(yàn)證,通過(guò)具體的代碼示例和操作步驟,詳細(xì)解釋了驗(yàn)證過(guò)程和相關(guān)配置,幫助讀者更好地理解和掌握使用這兩種驗(yàn)證工具的方法,更多Rust相關(guān)技術(shù)資訊,可繼續(xù)關(guān)注腳本之家2024-09-09
libbpf和Rust開(kāi)發(fā)ebpf程序?qū)崙?zhàn)示例
這篇文章主要為大家介紹了libbpf和Rust開(kāi)發(fā)ebpf程序?qū)崙?zhàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-12-12

