Node.js 應用探索文件解壓縮示例詳解

引言

今天在使用 node 腳本對文件處理時,需要實現一個功能,要對一個 zip 壓縮包解壓出來,修改裡面的文件後,重新打包成zip包。node 解壓縮文件的場景在實際應用中還是比較常見,下面介紹幾個用來解壓縮文件的庫和使用方法。

compressing

compressing 是一個使用起來方便、功能非常強大的node庫,它可以對文件、文件夾進行解壓或壓縮,支持tar、gzip、tgz、zip等多種格式。

簡單安裝之後 npm install compressing,以 zip 壓縮包為例

解壓

解壓比較簡單,tar、gzip、zip 都是同個 API

const compressing = require('compressing');
// 將壓縮包解壓到 test 文件夾中
compressing.zip.uncompress('./test.zip','./test').then(() => {
	console.log('解壓完成')
}).catch(() => {
	console.log('解壓失敗')
})
// 將壓縮包解壓到當前文件夾中
compressing.zip.uncompress('./test.zip','./')

壓縮

const compressing = require('compressing');
// 壓縮一個文件
compressing.zip.compressFile('E:/1.txt','E:/1.zip').then(() => {
	console.log('壓縮完成')
}).catch(() => {
	console.log('壓縮失敗')
})
// 壓縮一個文件夾
compressing.zip.compressDir('E:/test', 'E:/test.zip').then(func1).catch(func2);
// 同時壓縮多個文件和文件夾,采用 stream 的方式
const zipStream = new compressing.zip.Stream();
zipStream.addEntry('./test');
zipStream.addEntry('./1.txt');
zipStream.pipe(fs.createWriteStream('./test1.zip')).on('finish', ()=>{
	console.log('壓縮完成')
}).on('error', ()=>{
	console.log('壓縮失敗')
})

在使用compressing.zip.compressDir壓縮整個文件夾的時候,會把最外層的文件夾也一起壓縮,解壓出來又是一個完整的文件夾。但是我的需求時隻想把這個文件夾下的所有文件打包,直接解壓出來得到零散的很多個文件。

最初的想法呢是通過 fs的API對文件夾進行遍歷,用 addEntry 的方式打包,後來發現原來是可以設置參數的,隻是文檔中沒有表現出來,而且寫著:usually you don't need it ,導致我走瞭很多彎路。

後面在 addEntry 的接口文檔中看到瞭有個 opt.ignoreBase 的參數,才想到 compressDir 是不是也可以用。於是嘗試瞭一下,的確滿足瞭我的需求,含淚刪掉遍歷文件夾的代碼。

compressing.zip.compressDir('E:/test', 'E:/test.zip', {
	ignoreBase: true
})

基本上,一個解壓和壓縮的需求就可以完成瞭。可偏偏就遇到瞭個問題,在用 compressing 壓縮成一個zip包之後,在某個特殊的系統中,用系統自帶的解壓出來,文件都變成文件夾瞭,比如 app.js 是個js文件,解壓後變成一個名為 app.js 的文件夾。這就很尷尬瞭。

我嘗試瞭compressDiraddEntry的方式,最終得到的結果都一樣。於是乎,為瞭驗證是這個系統本身解壓算法的問題,我又找瞭另外一個壓縮庫。

archiver

archiver是一個在nodejs中能跨平臺實現打包功能的模塊,通過 stream 的方式,可以打zip和tar包。如果連這個打包之後在這個系統中解壓出來的文件還是有問題的話,那我就可以認為是這個系統的問題,而不是我代碼的問題。

const output = fs.createWriteStream('./test.zip');
const archive = archiver('zip', {zlib: {
	level: 9 // 設置壓縮等級
}});
archive.pipe(output);
archive.directory('./test', false); // 這裡false參數和上面的ignoreBase為true效果一樣
archive.finalize();	// 完成壓縮
archive.on('end', () => {	// 壓縮結束時觸發
	console.log('壓縮完成');
});

本來想證明是這個系統本身存在問題,結果卻狠狠打臉瞭。用 archiver 壓縮後的 zip 包在這個系統中解壓出來是正常的文件,那麼真相就是 compressing 的壓縮算法有點問題,隻不過這個問題復現的場景很不一般,在正常的系統中都不會遇到。

不過呢,我想瞭又想,現在也隻能算是一比一打平,為瞭科學的嚴謹性,我決定再找一個壓縮庫進行驗證。

adm-zip

adm-zip 是一個支持zip壓縮和解壓縮的庫,而我也隻需要壓縮zip格式包,剛好可以滿足我的需求。

壓縮

const admzip = new AdmZip();
// 壓縮文件夾
admzip.addLocalFolder('./test');
// 壓縮文件
admzip.addLocalFile('./1.txt');
admzip.writeZip('./test.zip');

addLocalFolder 壓縮整個文件夾的時候,會把這個文件夾下的所有文件打包,直接解壓出來得到零散的很多個文件,效果和compressDir設置參數ignoreBase為true一樣。

addLocalFolder 支持第二個參數,可以將要壓縮的文件,壓縮進壓縮包的某個路徑下。

admzip.addLocalFolder('./test','aaa');
admzip.addLocalFolder('./test','aaa/bbb');

可以設置多級目錄,解壓出來後的文件就在這個目錄裡。

writeZip 是一個同步的方法,而上面兩個庫壓縮都是異步的。在使用 adm-zip 打包之後,驗證出來的效果和 archiver 是一樣的,在那個特殊的系統上,解壓都沒有問題。這就真的證明瞭 compressing 真的存在小問題,不過在正常場景中應該都可以忽略不計。

解壓縮

adm-zip 也支持解壓縮。

const admzip = new AdmZip('./test.zip');
admzip.extractAllTo('./test'); // 把整個壓縮包完全解壓到 test 目錄中

除瞭解壓整個壓縮包,還支持單獨解壓某個文件

const admzip = new AdmZip('./test.zip');
const entry = zip.getEntry('1.txt');
admzip.extractEntryTo(entry, './test2', true, true);

extractEntryTo 支持4個參數,第三個參數表示是否需要創建父文件夾,第四個參數表示是否要覆蓋。

總結

經過多個庫的使用和對比,發現 adm-zip 可以完美的解決我的需求,同時打包之後,體積也是最小的。在大部分的開發場景中,用哪個庫其實都不會有問題的。compressing 可以支持更多的壓縮格式,adm-zip隻支持zip格式,archiver 卻不支持解壓縮,因此根據自己的應用場景選擇最合適的庫吧。

以上就是Node.js 應用探索文件解壓縮示例詳解的詳細內容,更多關於Node.js 文件解壓縮的資料請關註WalkonNet其它相關文章!

推薦閱讀: