用node写一个压缩文件的脚本

本文介绍了如何使用Node.js通过archiver模块创建zip压缩文件,并提供了使用示例。同时,作者推荐了在某些场景下使用tar工具,因其在Linux下功能更为丰富。

用node写一个压缩文件(zip格式)的脚本

缘起日常的发包没有运维自动化,本着不要 DRY 的原则,重复的流程应该写成自动化或半自动化的方式。

  1. 安装依赖 npm i --global archiver
  2. 实现逻辑思路:从路径读取文件(或目录),交给 archiver 处理压缩,输出结果
const fs = require('fs')
const path = require('path')
const archiver = require('archiver')

/**
 *
 * @param {String} source 打包文件路径
 * @param {String} target 输出文件路径
 */
function archivePackage(source, target, ignoreFile = []) {
  return new Promise((resolve, reject) => {
    const sourcePath = normalizePath(source)
    try {
      fs.accessSync(sourcePath, fs.constants.R_OK)
    } catch (error) {
      return reject(error)
    }

    // create a file to stream archive data to.
    const output = fs.createWriteStream(normalizePath(target))
    const archive = archiver('zip', {
      zlib: { level: 9 }, // Sets the compression level.
    })

    // listen for all archive data to be written
    // 'close' event is fired only when a file descriptor is involved
    output.on('close', function () {
      console.log(archive.pointer() + ' total bytes')
      console.log(
        'archiver has been finalized and the output file descriptor has closed.'
      )
      resolve()
    })

    // This event is fired when the data source is drained no matter what was the data source.
    // It is not part of this library but rather from the NodeJS Stream API.
    // @see: https://nodejs.org/api/stream.html#stream_event_end
    output.on('end', function () {
      console.log('Data has been drained')
    })

    // good practice to catch warnings (ie stat failures and other non-blocking errors)
    archive.on('warning', function (err) {
      if (err.code === 'ENOENT') {
        // log warning
      } else {
        // throw error
        throw err
      }
    })

    // good practice to catch this error explicitly
    archive.on('error', function (err) {
      reject()
      throw err
    })

    // pipe archive data to the file
    archive.pipe(output)

    // append files from a sub-directory and naming it `new-subdir` within the archive
    // archive.directory('subdir/', 'new-subdir');

    // append files from a sub-directory, putting its contents at the root of archive
    // archive.directory(normalizePath(source), false)

    // append files from a glob pattern
    //? sometheing suggestion ref: https://stackoverflow.com/questions/65960979/node-js-archiver-need-syntax-for-excluding-file-types-via-glob
    //? 目前ignore 选项不能忽略文件夹
    archive.glob('**/*', { cwd: normalizePath(source), ignore: ignoreFile })

    // finalize the archive (ie we are done appending files but streams have to finish yet)
    // 'close', 'end' or 'finish' may be fired right after calling this method so register to them beforehand
    archive.finalize()
  })
}

function normalizePath(pathStr) {
  return path.resolve(pathStr.replace(/^[A-Z]{1}:/gi, '').replace(/\\/g, '/'))
}

function cleanFile(pathStr) {
  if (fs.existsSync(pathStr)) {
    const stat = fs.statSync(pathStr)
    if (stat.isDirectory()) {
      fs.rmSync(pathStr, { recursive: true })
    } else if (stat.isFile()) {
      fs.unlinkSync(pathStr)
    }
  }
}
function cleanPrepareDir(pathStr) {
  cleanFile(pathStr)
  fs.mkdirSync(pathStr)
}

function copyFile(sourcePath, targetPath) {
  fs.copyFileSync(sourcePath, targetPath)
  console.log(`copy ${sourcePath} to ${targetPath} successed.`)
}

function main() {
  // 根目录只能是当前执行的盘符 此处 / = D:
  let today = new Date().toISOString().split(/T/)[0].replace(/-/g, '')
  const packagePath = `/前端包/前端包${today}`
  const packagePathZip = `${packagePath}.zip`
  cleanPrepareDir(packagePath)
  cleanFile(packagePathZip)

  // 根据实际需要 copy 文件到目标目录
  copyFile('./readme.md', `${packagePath}/readme.md`)
  const p1 = archivePackage(
    '/work/git_project/dist',
    `${packagePath}/dist.zip`,
    ['**/.vscode/**/*', '**/.env*']
  )

  const p2 = archivePackage(
    '/work/svn_project/public',
    `${packagePath}/public.zip`,
    ['**/.vscode/**/*', '**/.env*']
  )
  Promise.all([p1, p2])
    .then(() => {
      archivePackage(packagePath, packagePathZip)
    })
    .catch((err) => {
      console.error('打包出错:', err)
      throw err
    })
}

main()

这个脚本是放到项目中打包使用,没有过多做配置。有实际需求可以使用 minimist 库解析参数,路径作为参数输入。

注意

注意: 在windows下,如果输入路径和输出路径不在同一个根盘符路径下,需要在执行过程中切换当前脚本工作路径。用到 process.chdir()。例如,输入文件为:D:\\app, 输出路径为:E:\\output ,需要在
D盘下执行,执行打包内容后 ,process.chdir("E:\\") 切换盘符再输出 压缩后的文件。同理,可以在任何盘符下执行,对应切换盘符找到文件路径即可。

推荐 tar

node 的压缩工具包还有一个 tar 的包,是 node 实现 linux 下的 tar 功能更丰富、压缩率更高,不过不支持 zip 格式文件,因此没有使用。没有格式要求,强烈建议使用 tar

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值