ZJONSSON/node-unzipper

unzipper.Parser doesn't work if zip contains >=2 files

mstmustisnt opened this issue · 1 comments

UPD: sometimes it works with 2 and more files, the thing is in file contents (?)
unzipper.Parse doesn't work if zip contains more than 1 file

Example:

const path = require('path');
const fs = require('fs');
const unzipper = require('unzipper');

const saveEntry = (
  entry,
  destinationFilePath
) => {
  return new Promise((resolve, reject) => {
    const writable = fs.createWriteStream(destinationFilePath);
    entry
      .pipe(writable)
      .on('finish', resolve)
      .on('error', reject);
  });
};

const extractFromZip = async (
  filePath,
  destinationPath
) => {
  const entries = [];
  const fileStream = fs.createReadStream(filePath);
  await new Promise((resolve, reject) => {
    fileStream
      .pipe(unzipper.Parse({ verbose: true }))
      .on('entry', (entry) => {
        entry.path = path.basename(entry.path);
        entries.push(entry);
      })
      .on('finish', resolve)
      .on('error', reject);
  });

  return Promise.all(
    entries.map(async (entry) => {
      const filePath = path.join(destinationPath, entry.path);
      await saveEntry(entry, filePath);

      return filePath;
    })
  );
};

const filePath = path.join(__dirname, 'file-one.zip'); // zip containing one file - works well
// zip containing 2 files
// - doesn't work, 'entry' event emitted only once, 'finish' not emitted
const fileMultiplePath = path.join(__dirname, 'file-multiple.zip'); 
const destPath = path.join(__dirname);

extractFromZip(fileMultiplePath, destPath).then(console.info.bind(console, 'finish')).catch(console.error);

finish and error events are never emitted, and the process ends with no errors and no unzipped files

In unzipper's legacy streaming version, each entry must be consumed as it's being streamed. So you can't collect entries into an array and then process them later.

so instead of

 entries.push(entry);

You should try consuming the entry at that point:

const filePath = path.join(destinationPath, entry.path);
await saveEntry(entry, filePath);