用node.js在Windows或Linux平台上高性能解压/压缩zip、tar大文件,输出到文件或Stream流


发布者 ourjs  发布时间 1584703762929
关键字 Node.JS 

之前介绍过一些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);

 

参考: NodeJS 文件(夹)压缩/解压方案

 

大文件解压

这些开源项目,基本都是加载到内存中处理,导致性能不佳,文件过大时还会提示内存无法分配的错误,此时可使用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)
})

 

 









 热门文章 - 分享最多
  1. OnceDB:使用Redis全文字符串模糊搜索,多条件查询,创建索引搜索等使用帮助教程
  2. Node.JS中回调嵌套和async/await执行空函数性能效率对比测试
  3. 怎么通过OnceOA免费实现外网访问家庭、企业内网服务器网站、网盘、办公系统
  4. SVG矢量图视窗viewBox,嵌套HTML综合实例:建立用户自定义相对坐标系统
  5. 用CSS实现分页符,控制Web网页打印时自动强制分页:page-break-after教程
  6. Node.JS如何按顺序调用async函数,如何判断是否为async函数,在mocha中自动化测试async/await代码
  7. node.js将回调函数嵌套,用promise改造成async/await顺序执行:异常处理和返回多个参数
  8. 用旺司OnceOA免费搭建企业多人知识文档管理协作办公软件
  9. 基于Node.JS和Electron编写的集成开发环境 VS Code,成为最受欢迎的IDE
  10. 使用node.js和oAuth2协议集成Github/LinkedIn第三方登录以OnceOA模块源码为例

 相关阅读
  1. Node.JS发送http请求批量检查文件中的网页地址、服务是否有效可用
  2. Node.JS的竞争对手?QuickJS入门教程,使用os模块读写文件,并将JavaScript编绎成可执行文件
  3. Node.JS用RSA签名算法公钥加密私钥解密,实现License软件授权验证
  4. Node.JS借助OS模块获取当前Windows系统用户登录名
  5. Node.JS在命令行中检查Chrome浏览器是否安装,并打开指定网址
  6. node.js中将console.log日志内容输出到文件
  7. 使用Node.JS批量查找替换目录下文本文件中图片地址内容
  8. 判断Node.JS TCP Socket当前连接状态
  9. Node.JS进程间通讯的几种方法:Redis Publish/Subscribe 和 UDP Socket
  10. Node.JS命令行或批处理中更改Linux用户密码

  开源的 OurJS
OurJS开源博客已经迁移到 OnceOA 平台。

  关注我们
扫一扫即可关注我们:
OnceJS

OnceOA