4

I am trying to use yauzl to unzip files. However the example in the repo does not show how to unzip to a folder. It simply says:

readStream.pipe(somewhere);

Is there an easy way to extract the contents to a folder?

Naresh
  • 23,937
  • 33
  • 132
  • 204

2 Answers2

0

Hi :) Replacing 'readStream.pipe(somewhere);' with code under '//--------------------' tag below works for me and the example in the repo

import fs = require('fs');
const unzipper = require('unzipper');
const { pipeline, finished } = require('stream');

//--------------------

cons destDir = 'C:\MyPath'
const writer = fs.createWriteStream(path.join(destDir, entry.fileName));
readStream.pipe(writer);

await finished(readStream, (err) => {
    if (err) {
          console.error(' ### Streaming to writer failed: ', err);
    } else {
        console.log(' ### Streaming to writer succeded, file unzipped.');
    }
};

DISCLAIMER: I am at the beginning of learning Node/ts! This works for me, but may be wrong to some reason/s.

forestgril
  • 85
  • 7
0

Here's a promise returning function that does what you're asking with the following caveats:

  • I have used mkdirp external library. This can be removed if you're more careful with how you create your directories.
  • I have not tested unzipping on top of an existing directory.
  • The zipFile.close() statements before the rejects may be unnecessary.
import path = require('path');
import yauzl = require('yauzl');
import mkdirp = require('mkdirp');

/**
 * Example:
 * 
 * await unzip("./tim.zip", "./");
 * 
 * Will create directories:
 * 
 * ./tim.zip
 * ./tim
 * 
 * @param zipPath Path to zip file.
 * @param unzipToDir Path to the folder where the zip folder will be put.
 */
const unzip = (zipPath: string, unzipToDir: string) => {
    return new Promise<void>((resolve, reject) => {
        try {
            // Create folder if not exists
            mkdirp.sync(unzipToDir);

            // Same as example we open the zip.
            yauzl.open(zipPath, { lazyEntries: true }, (err, zipFile) => {
                if (err) {
                    zipFile.close();
                    reject(err);
                    return;
                }

                // This is the key. We start by reading the first entry.
                zipFile.readEntry();

                // Now for every entry, we will write a file or dir 
                // to disk. Then call zipFile.readEntry() again to
                // trigger the next cycle.
                zipFile.on('entry', (entry) => {
                    try {
                        // Directories
                        if (/\/$/.test(entry.fileName)) {
                            // Create the directory then read the next entry.
                            mkdirp.sync(path.join(unzipToDir, entry.fileName));
                            zipFile.readEntry();
                        }
                        // Files
                        else {
                            // Write the file to disk.
                            zipFile.openReadStream(entry, (readErr, readStream) => {
                                if (readErr) {
                                    zipFile.close();
                                    reject(readErr);
                                    return;
                                }

                                const file = fs.createWriteStream(path.join(unzipToDir, entry.fileName));
                                readStream.pipe(file);
                                file.on('finish', () => {
                                    // Wait until the file is finished writing, then read the next entry.
                                    // @ts-ignore: Typing for close() is wrong.
                                    file.close(() => {
                                        zipFile.readEntry();
                                    });

                                    file.on('error', (err) => {
                                        zipFile.close();
                                        reject(err);
                                    });
                            });
                        }
                    }
                    catch (e) {
                        zipFile.close();
                        reject(e);
                    }
                });
                zipFile.on('end', (err) => {
                    resolve();
                });
                zipFile.on('error', (err) => {
                    zipFile.close();
                    reject(err);
                });
            });
        }
        catch (e) {
            reject(e);
        }
    });
}
jmathew
  • 1,522
  • 17
  • 29