使用Rust的ripunzip和rayon並行解壓縮檔案
並行解壓縮檔案,除了 zip 庫本身,這裡的關鍵庫是rayon。Rayon 為我們提供了諸如並行迭代器之類的東西,以最小的麻煩線上程池中分配任務。
mkdir ripunzip; cd ripunzip cargo init cargo add clap --features=derive cargo add rayon cargo add zip cargo add anyhow cargo run --release |
檔案克隆:
#[derive(Clone)] struct CloneableFile { file: Arc<Mutex<File>>, pos: u64, // TODO determine and store this once instead of per cloneable file file_length: Option<u64>, } impl CloneableFile { fn new(file: File) -> Self { Self { file: Arc::new(Mutex::new(file)), pos: 0u64, file_length: None, } } } impl CloneableFile { fn ascertain_file_length(&mut self) -> u64 { match self.file_length { Some(file_length) => file_length, None => { let len = self.file.lock().unwrap().metadata().unwrap().len(); self.file_length = Some(len); len } } } } impl Read for CloneableFile { fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> { let mut underlying_file = self.file.lock().expect("Unable to get underlying file"); // TODO share an object which knows current position to avoid unnecessary // seeks underlying_file.seek(SeekFrom::Start(self.pos))?; let read_result = underlying_file.read(buf); if let Ok(bytes_read) = read_result { // TODO, once stabilised, use checked_add_signed self.pos += bytes_read as u64; } read_result } } impl Seek for CloneableFile { fn seek(&mut self, pos: SeekFrom) -> std::io::Result<u64> { let new_pos = match pos { SeekFrom::Start(pos) => pos, SeekFrom::End(offset_from_end) => { let file_len = self.ascertain_file_length(); // TODO, once stabilised, use checked_add_signed file_len - (-offset_from_end as u64) } // TODO, once stabilised, use checked_add_signed SeekFrom::Current(offset_from_pos) => { if offset_from_pos == 0 { self.pos } else if offset_from_pos > 0 { self.pos + (offset_from_pos as u64) } else { self.pos - ((-offset_from_pos) as u64) } } }; self.pos = new_pos; Ok(new_pos) } } |
在這裡,我們只是將檔案儲存為Arc<Mutex<File>>,但隨後我們需要實現Read和Seek。
main函式:
fn main() -> Result<()> { let args = Args::parse(); let zipfile = File::open(args.zipfile)?; let zipfile = CloneableFile::new(zipfile); let zip = zip::ZipArchive::new(zipfile)?; let file_count = zip.len(); println!("Zip has {} files", file_count); (0..file_count).into_par_iter().for_each(|i| { let mut myzip = zip.clone(); let mut file = myzip.by_index(i).expect("Unable to get file from zip"); if file.is_dir() { return; } let out_file = file.enclosed_name().unwrap(); println!("Filename: {}", out_file.display()); if let Some(parent) = out_file.parent() { create_dir_all(parent).unwrap_or_else(|err| { panic!( "Unable to create parent directories for {}: {}", out_file.display(), err ) }); } let mut out_file = File::create(out_file).unwrap(); std::io::copy(&mut file, &mut out_file).unwrap(); }); Ok(()) } |
對於一個 (2.5GB) Mac ASAN 構建,速度差異很大…
unzip: real 1m10.807s user 0m55.483s sys 0m6.637s ripunzip: real 0m13.193s user 0m39.767s sys 0m43.872s |
相關文章
- betterzip怎麼解壓檔案?如何使用BetterZip批次解壓壓縮檔案
- .NET 壓縮/解壓檔案
- Linux中Bin檔案壓縮包解壓執行Linux
- 使用Java API進行tar.gz檔案及資料夾壓縮解壓縮JavaAPI
- 電腦怎麼壓縮檔案 檔案壓縮方法詳解
- Linux下檔案的壓縮與解壓Linux
- 使用libzip壓縮檔案和資料夾
- 檔案壓縮和解壓縮
- linux 下面壓縮、解壓.rar檔案Linux
- Linux中檔案的壓縮和解壓縮Linux
- 分卷壓縮怎麼解壓 快速解壓電腦分卷壓縮檔案方法
- 使用os.walk提取壓縮檔案並避免遞迴提取遞迴
- tar解壓到指定目錄並去掉壓縮檔案的層級資料夾
- 教你如何在 Linux 中使用 unzip 解壓縮檔案Linux
- Java實現解壓縮檔案和資料夾Java
- Linux科研武器庫 - 檔案壓縮與解壓縮 - zip / unzipLinux
- linux系統壓縮,解壓檔案筆記Linux筆記
- Linux 檔案壓縮Linux
- gulp壓縮檔案
- 哈夫曼實現檔案壓縮解壓縮(c語言)C語言
- python 壓縮檔案並進行郵件傳送(附件格式為zip)Python
- Linux常用命令之檔案壓縮與解壓縮命令詳解Linux
- python解壓並讀取檔案Python
- c# 檔案壓縮DotNetZip和SharpZipLibC#
- Laravel 中建立 Zip 壓縮檔案並提供下載Laravel
- 批處理 壓縮zip 並過濾部分檔案
- Mac壓縮檔案怎麼加密?BetterZip加密Word壓縮檔案教程Mac加密
- linux檔案壓縮和解壓命令Linux
- 壓縮檔案格式rar和zip有什麼區別 壓縮檔案格式rar和zip哪個好
- c# 上傳壓縮包 解壓,遍歷資料夾和檔案C#
- linux 高效壓縮工具之xz的壓縮解壓使用Linux
- linuxtar解壓和壓縮Linux
- NCH ExpressZip Plus for mac(檔案解壓縮工具)ExpressMac
- Ubuntu 壓縮檔案命令Ubuntu
- c#壓縮檔案C#
- 如何使用Commander One Mac來壓縮檔案?Mac
- 【Go】使用壓縮檔案優化io (二)Go優化
- 【Go】使用壓縮檔案優化io (一)Go優化