如何计算节点归档器内容长度

问题描述 投票:0回答:1

我正在使用 archiver lib 动态压缩文件并将 zip 流直接发送到客户端浏览器,它可以工作,但是有一个问题 - 它没有显示进度,因为我没有提供内容长度。如何提前计算内容长度?就我而言,文件的长度是已知的,但最终存档的大小大于所有文件的总和。之所以如此,是因为我的存档中有文件夹。那么如何单独计算文件夹大小呢?这样我就可以使用 - FilesSize + FoldesrSize = Contentlength。我选择压缩作为存储。

node.js zip node-archiver
1个回答
0
投票

我在尝试解决同样的问题时遇到了这个问题,有点晚了,但我希望这对某人有帮助。

我基本上解决了这个问题,首先通过流式传输到操作系统临时目录来模拟过程,我获取了内容长度,然后将包含内容长度的目标文件夹流式传输到客户端。下面是 Typescript 中的代码片段:

// imports
import { tmpdir } from 'os'
import { createReadStream, createWriteStream } from 'fs'
import { Readable } from 'stream'
import { Response } from 'express'
import archiver from 'archiver'

// object to store the simulation result
class ZipSimulationResult {
  simulatedSize: number
  destination: string
}

// in this case, I pass an array of Readable streams, 
// but you can easily create a Readable stream from your files instead
async function simulateZipStream(
  streamArr: Readable[]
): Promise<ZipSimulationResult> {
  return new Promise((resolve, reject) => {
    const tempDir = tmpdir()
    const destination = `${tempDir}/${Date.now()}.zip`
    const destinationStream = createWriteStream(destination)
    const archive = archiver('zip')

    archive.pipe(destinationStream)

    for (let i = 0; i < streamArr.length; i++) {
      // you probably need the file extension as well for the 
      // file name, edit the code according to your needs
      archive.append(streamArr[i], { name: `file_${i}` })
    }

    archive.on('error', function (err) {
      console.error('Error while simulating zip: ', err)
      reject(err)
    })

    archive.on('end', () => {
      console.log('simulated archive size: ' + archive.pointer())
      const result = new ZipSimulationResult()
      result.destination = destination
      // archive.pointer() returns the totalBytes wrote by archiver
      result.simulatedSize = archive.pointer()
      resolve(result)
    })

    archive.finalize()
  })
}

/// To use
/// Re-write this to suit your use case
async function zipAndStream(
  zipFileName: string,
  streamArr: Readable[],
  res: Response
) {
  const simulationResult = await simulateZipStream(streamArr)
  const zipReadStream = createReadStream(simulationResult.destination)
  res.setHeader('content-length', simulationResult.simulatedSize)
  res.setHeader('content-type', 'application/zip')
  res.setHeader(
    'content-disposition',
    `attachment; filename="${zipFileName}.zip"`
  )
  // you could also listen to the 'error' event on 'res'
  zipReadStream.pipe(res)
}
© www.soinside.com 2019 - 2024. All rights reserved.