之前介绍过一些node.js模块,可用原生JS实现zip文件解压,特点是无第三方依赖,跨平台,部署简单。
node.js模块
目前有很多模块,比如:adm-zip, JSZip, archiver/ unzip
var adm_zip = require('adm-zip');
//creating archives
var zip = new adm_zip();
zip.addLocalFolder('archiver');
zip.writeZip('adm/adm-archive.zip');
//extracting archives
var unzip = new adm_zip('adm/adm-archive.zip');
unzip.extractAllTo("adm/adm-unarchive/", /*overwrite*/true);
大文件解压
这些开源项目,基本都是加载到内存中处理,导致性能不佳,文件过大时还会提示内存无法分配的错误,此时可使用Windows或Linux下的一些原生应用来实现。
Windows
可使用7zip,在node.js中调用7zip即可。
Linux
可使用 zip/unzip/tar 等命令。
调用时需要使用 cp.spawn 方法,在子进程用流来输出或写入,使用前需要先了解这些命令的调用参数。 示例代码如下:
var fs = require('fs')
var cp = require('child_process')
var os = require('os')
var path = require('path')
if (!String.prototype.format) {
Object.defineProperties(String.prototype, {
format: {
enumerable: false,
value: function() {
var str = this.toString();
if (!arguments.length)
return str;
var args = typeof arguments[0],
args = (("string" == args || "number" == args) ? arguments : arguments[0]);
for (arg in args)
str = str.replace(RegExp("\\{" + arg + "\\}", "gi"), args[arg]);
return str;
}
}
});
}
var isWin32 = os.platform() == 'win32'
/*
Windows: 手动下载 7zip 或者 zip
http://www.7-zip.org/download.html
Debian: 安装 zip/unzip
apt-get install zip/unzip
*/
var path7Zip = ''
var get7ZipPath = function() {
var zipPath = 'C:\\Program Files\\7-Zip\\7z.exe'
fs.stat(zipPath, function(err, states) {
if (states) {
path7Zip = zipPath
return
}
zipPath = 'C:\\Program Files (x86)\\7-Zip\\7z.exe'
fs.stat(zipPath, function(err, states) {
if (states) {
path7Zip = zipPath
return
}
console.log('7zip not found')
})
})
}
isWin32 && get7ZipPath()
var getShortDir = function(inputs) {
if (!Array.isArray(inputs)) {
return path.dirname(inputs)
}
var shortDir = path.dirname(inputs[0])
for (var i = 1; i < inputs.length; i++) {
var input = inputs[i]
var tmpDir = path.dirname(input)
if (shortDir > tmpDir) {
shortDir = tmpDir
}
}
var result = []
for (var i = 0; i < inputs.length; i++) {
var input = inputs[i]
var tmpDir = path.relative(shortDir, input)
result.push(tmpDir)
}
return shortDir
}
var zip = function(input, output, cb) {
var isOutStream = output && output.pipe
var isInputArr = Array.isArray(input)
var zipHandler = function(err, states) {
var exePath = ''
var params
var isOutDir = states && states.isDirectory()
var archive_name = ''
if (isOutDir || isOutStream) {
//输出是目录或者流,文件名从输入获取
archive_name = path.basename(isInputArr ? input[0] : input) + '.zip'
} else {
//输出是文件名
archive_name = path.basename(output)
}
if (isOutStream) {
if (isWin32) {
//7z x archive.gz -so > Doc.txt
//7z a dummy -tgzip -so Doc.txt > archive.gz
exePath = path7Zip
params = ['a', '-tzip', '-so', archive_name]
} else {
//zip -r - files_to_be_archived | nc remotehost 8787
exePath = 'zip'
params = ['-r', '-']
}
} else {
var output_dir = ''
if (isOutDir) {
output_dir = output
} else {
output_dir = path.dirname(output)
}
var archive_path = path.join(output_dir, archive_name)
if (isWin32) {
//7z.exe' a -tzip -y onceio D:\\github\\oncedoc\\oncedoc\\svr\\onceio
exePath = path7Zip
params = ['a', '-tzip', '-y', archive_path]
} else {
//zip -r yasuo.zip abc.txt dir1
exePath = 'zip'
params = ['-r', archive_path]
}
}
if (isInputArr) {
params = params.concat(input)
} else {
params.push(input)
}
console.log(exePath)
console.log(params)
var zipProc = cp.spawn(exePath, params)
var errMsg = ''
var outMsg = ''
isOutStream && zipProc.stdout.pipe(output)
zipProc.stderr.on('data', function (data) {
errMsg += data.toString()
})
zipProc.on('close', function(code) {
var err = null
cb && cb(err)
})
}
isOutStream
? zipHandler()
: fs.stat(output, zipHandler)
}
var unzip = function(zipPath, output_dir, cb) {
fs.stat(zipPath, function(err, states) {
if (err || states.isDirectory()) {
console.log('input is not zip file')
cb && cb(err)
return
}
fs.stat(output_dir, function(err, states) {
var exePath = ''
var params
if (states && states.isDirectory()) {
if (isWin32) {
//7z e archive.zip -oC:\soft *.cpp -r
exePath = path7Zip
params = ['x', zipPath, '-o' + output_dir, '-y']
} else {
//unzip yasuo.zip
exePath = 'unzip'
params = ['-o', zipPath, '-d', output_dir]
}
} else {
if (isWin32) {
exePath = path7Zip
params = ['x', zipPath, '-so', output_dir]
} else {
exePath = 'unzip'
params = ['-p', zipPath, output_dir]
}
}
console.log(exePath, params)
var zipProc = cp.spawn(exePath, params)
var errMsg = ''
var outMsg = []
zipProc.stdout.on('data', function (data) {
console.log(data.toString())
outMsg.push(data)
})
zipProc.stderr.on('data', function (data) {
console.log(data.toString())
errMsg += data.toString()
})
zipProc.on('close', function(code) {
var err = null
if (errMsg) {
err = new Error(errMsg)
}
console.log(errMsg)
//console.log(outMsg)
cb && cb(err, Buffer.concat(outMsg))
})
})
})
}
var tar = function(folderPath, tarGzName, cb) {
var idx = tarGzName.lastIndexOf('.')
var tarName = tarGzName.substr(0, idx)
//7z a -ttar -so dwt.tar dwt/ | 7z a -si dwt.tar.gz
cp.exec('"{0}" a -ttar -so {1} {2} | "{0}" a -si {3}'.format(
path7Zip
, tarName
, folderPath
, tarGzName
), cb)
}
module.exports = {
zip : zip
, unzip : unzip
, tar : tar
}
比如上面的文件命名为zip.js,则使用时:
var Zip = require('./zip')
var zip = Zip.zip
var unzip = Zip.unzip
zip('./onceio', '../', function() {
console.log('zipped')
})
unzip('../onceio.zip', '../')
unzip('../onceio.zip', 'onceio/onceio.js', function(err, content) {
console.log(err)
})
zip(['./onceio', './oncedb'], '../oncelal.zip', function() {
console.log(arguments)
})
另外此方法还支持输出到流,比如说浏览器响应流res,或命令行终端stdout:
zip('./zip-util.js', process.stdout, function() {
console.log(arguments)
})
回复 (0)
微信扫码 立即评论