在 Node.js 中有很多与zip压缩解压相关的库,比如 node-unzip, adm-zip, archiver等。不过在低端ARM芯片压缩大目录时,会非常慢。
其实 Node.JS 是不太适合计算密集型的压缩与解压指令的,在较便宜的嵌入式设备上的性能并不是很好。
并且archiver/node-unzip 这些包也非常大,要占用几M的空。其实使用 7zip(windows)/ zip(linux) 等这些用C/C++写的软件,简单封装一下,性能就能很好地提升。
使用系统软件压缩与解压
首先需要在 Windows 电脑上安装 7-zip,在linux电脑上安装 zip (apt-get install zip)
然后在命令街上测试,比如将当前 onceio 目录写入上一级的 onceio.zip
Linux
zip -r ../onceio.zip ./onceio
Windows:
"C:\\Program Files\\7-Zip\\7z.exe" a -tzip ..\\onceio.zip ./onceio
将解压/解压结构输出到流
这里有一个难点,就是怎么样把输出结果输出到流。
比如说网页要下载很多文件,最好将这些文件压缩入流然后直接输出到 response,这样就不需要先创建这个文件了,内容也不需要预先装入内存或磁盘了。
其实几乎所有的命令行工具都支持将从命令行输入输出数据。我们只需要将流对象与stdin/stdout流pipe一下即可。
Linux: 将文件压缩到当前命令行(stdout),-表示不写入文件
zip -r - ./zip-util.js
Windows: -so 参数表示将结果输出到stdout
# 将 archive.gz 通过流写入 doc.txt
7z x archive.gz -so > Doc.txt
# 将 Doc.txt 压缩入 archive.gz
7z a dummy -tgzip -so Doc.txt > archive.gz
Node.JS代码参考
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) { //https://superuser.com/questions/148498/7zip-how-to-extract-to-std-output 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 { //https://stackoverflow.com/questions/18933975/zip-file-and-print-to-stdout //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 { //https://www.cnblogs.com/chinareny2k/archive/2010/01/05/1639468.html //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 // if (errMsg) { // err = new Error(errMsg) // } console.log(errMsg) //console.log(outMsg) cb && cb(err) }) } isOutStream ? zipHandler() : fs.stat(output, zipHandler) }
使用示例
将 onceio 压缩到上一级目录,会自动命名为 onceio.zip
zip('./onceio', '../', function() {
console.log('zipped')
})
将 oncedb 压缩到上一级目录的 oncedb.new.zip
zip('./oncedb', '../oncedb.new.zip', function() {
console.log('zipped')
})
压缩多个目录
zip(['./onceio', './oncedb'], '../oncelal.zip', function() {
console.log(arguments)
})
将文件压缩到主进程输出流 process.stdout
zip('./zip-util.js', process.stdout, function() {
console.log(arguments)
})
附:7zip与zip更更参数详解
Usage: 7z <command> [<switches>...] <archive_name> [<file_names>...] <Commands> a : Add files to archive b : Benchmark d : Delete files from archive e : Extract files from archive (without using directory names) h : Calculate hash values for files i : Show information about supported formats l : List contents of archive rn : Rename files in archive t : Test integrity of archive u : Update files to archive x : eXtract files with full paths <Switches> -- : Stop switches parsing @listfile : set path to listfile that contains file names -ai[r[-|0]]{@listfile|!wildcard} : Include archives -ax[r[-|0]]{@listfile|!wildcard} : eXclude archives -ao{a|s|t|u} : set Overwrite mode -an : disable archive_name field -bb[0-3] : set output log level -bd : disable progress indicator -bs{o|e|p}{0|1|2} : set output stream for output/error/progress line -bt : show execution time statistics -i[r[-|0]]{@listfile|!wildcard} : Include filenames -m{Parameters} : set compression Method -mmt[N] : set number of CPU threads -mx[N] : set compression level: -mx1 (fastest) ... -mx9 (ultra) -o{Directory} : set Output directory -p{Password} : set Password -r[-|0] : Recurse subdirectories -sa{a|e|s} : set Archive name mode -scc{UTF-8|WIN|DOS} : set charset for for console input/output -scs{UTF-8|UTF-16LE|UTF-16BE|WIN|DOS|{id}} : set charset for list files -scrc[CRC32|CRC64|SHA1|SHA256|*] : set hash function for x, e, h commands -sdel : delete files after compression -seml[.] : send archive by email -sfx[{name}] : Create SFX archive -si[{name}] : read data from stdin -slp : set Large Pages mode -slt : show technical information for l (List) command -snh : store hard links as links -snl : store symbolic links as links -sni : store NT security information -sns[-] : store NTFS alternate streams -so : write data to stdout -spd : disable wildcard matching for file names -spe : eliminate duplication of root folder for extract command -spf : use fully qualified file paths -ssc[-] : set sensitive case mode -sse : stop archive creating, if it can't open some input file -ssw : compress shared files -stl : set archive timestamp from the most recently modified file -stm{HexMask} : set CPU thread affinity mask (hexadecimal number) -stx{Type} : exclude archive type -t{Type} : Set type of archive -u[-][p#][q#][r#][x#][y#][z#][!newArchiveName] : Update options -v{Size}[b|k|m|g] : Create volumes -w[{path}] : assign Work directory. Empty path means a temporary directory -x[r[-|0]]{@listfile|!wildcard} : eXclude filenames -y : assume Yes on all queries zip [-options] [-b path] [-t mmddyyyy] [-n suffixes] [zipfile list] [-xi list] The default action is to add or replace zipfile entries from list, which can include the special name - to compress standard input. If zipfile and list are omitted, zip compresses stdin to stdout. -f freshen: only changed files -u update: only changed or new files -d delete entries in zipfile -m move into zipfile (delete OS files) -r recurse into directories -j junk (don't record) directory names -0 store only -l convert LF to CR LF (-ll CR LF to LF) -1 compress faster -9 compress better -q quiet operation -v verbose operation/print version info -c add one-line comments -z add zipfile comment -@ read names from stdin -o make zipfile as old as latest entry -x exclude the following names -i include only the following names -F fix zipfile (-FF try harder) -D do not add directory entries -A adjust self-extracting exe -J junk zipfile prefix (unzipsfx) -T test zipfile integrity -X eXclude eXtra file attributes -y store symbolic links as the link instead of the referenced file -e encrypt -n don't compress these suffixes
相关阅读:
Node.JS高效压缩解压zip文件:将child_process执行结果输入stdout流
NodeJS 文件压缩/解压方案-Linux上zip相关命令
回复 (0)
微信扫码 立即评论