msikora
msikora

Reputation: 507

Zip archives in node.js

I want to create a zip archive and unzip it in node.js.

I can't find any node implementation.

Upvotes: 49

Views: 57927

Answers (10)

Eliseo Soto
Eliseo Soto

Reputation: 1302

I ended up doing it like this (I'm using Express). I'm creating a ZIP that contains all the files on a given directory (SCRIPTS_PATH).

I've only tested this on Mac OS X Lion, but I guess it'll work just fine on Linux and Windows with Cygwin installed.

var spawn = require('child_process').spawn;
app.get('/scripts/archive', function(req, res) {
    // Options -r recursive -j ignore directory info - redirect to stdout
    var zip = spawn('zip', ['-rj', '-', SCRIPTS_PATH]);

    res.contentType('zip');

    // Keep writing stdout to res
    zip.stdout.on('data', function (data) {
        res.write(data);
    });

    zip.stderr.on('data', function (data) {
        // Uncomment to see the files being added
        // console.log('zip stderr: ' + data);
    });

    // End the response on zip exit
    zip.on('exit', function (code) {
        if(code !== 0) {
            res.statusCode = 500;
            console.log('zip process exited with code ' + code);
            res.end();
        } else {
            res.end();
        }
    });
});

Upvotes: 29

Todd Price
Todd Price

Reputation: 2760

I've found it easiest to roll my own wrapper around 7-zip, but you could just as easily use zip or whatever command line zip tool is available in your runtime environment. This particular module just does one thing: zip a directory.

const { spawn } = require('child_process');
const path = require('path');

module.exports = (directory, zipfile, log) => {
  return new Promise((resolve, reject) => {
    if (!log) log = console;

    try {
      const zipArgs = ['a', zipfile, path.join(directory, '*')];
      log.info('zip args', zipArgs);
      const zipProcess = spawn('7z', zipArgs);
      zipProcess.stdout.on('data', message => {
        // received a message sent from the 7z process
        log.info(message.toString());
      });

      // end the input stream and allow the process to exit
      zipProcess.on('error', (err) => {
        log.error('err contains: ' + err);
        throw err;
      });

      zipProcess.on('close', (code) => {
        log.info('The 7z exit code was: ' + code);
        if (code != 0) throw '7zip exited with an error'; // throw and let the handler below log it
        else {
          log.info('7zip complete');
          return resolve();
        }
      });
    }
    catch(err) {
      return reject(err);
    }
  });
}

Use it like this, assuming you've saved the above code into zipdir.js. The third log param is optional. Use it if you have a custom logger. Or delete my obnoxious log statements entirely.

const zipdir = require('./zipdir');

(async () => {
  await zipdir('/path/to/my/directory', '/path/to/file.zip');
})();

Upvotes: 1

Ragnar
Ragnar

Reputation: 4578

You can use archiver module, it was very helpful for me, here is an example:

var Archiver = require('archiver'),
    fs = require('fs');
app.get('download-zip-file', function(req, res){    
    var archive = Archiver('zip');
    archive.on('error', function(err) {
        res.status(500).send({error: err.message});
    });
    //on stream closed we can end the request
    res.on('close', function() {
        console.log('Archive wrote %d bytes', archive.pointer());
        return res.status(200).send('OK').end();
    });
    //set the archive name
    res.attachment('file-txt.zip');
    //this is the streaming magic
    archive.pipe(res);
    archive.append(fs.createReadStream('mydir/file.txt'), {name:'file.txt'});
    //you can add a directory using directory function
    //archive.directory(dirPath, false);
    archive.finalize();
});

Upvotes: 7

WaughWaugh
WaughWaugh

Reputation: 1032

I have used 'archiver' for zipping files. Here is one of the Stackoverflow link which shows how to use it, Stackoverflow link for zipping files with archiver

Upvotes: 1

MateodelNorte
MateodelNorte

Reputation: 1280

node-core has built in zip features: http://nodejs.org/api/zlib.html

Use them:

var zlib = require('zlib');
var gzip = zlib.createGzip();
var fs = require('fs');
var inp = fs.createReadStream('input.txt');
var out = fs.createWriteStream('input.txt.gz');

inp.pipe(gzip).pipe(out);

Upvotes: 29

Tomasz Janczuk
Tomasz Janczuk

Reputation: 3248

You can use the edge.js module that supports interop between node.js and .NET in-process, and then call into .NET framework's ZipFile class which allows you to manipulate ZIP archives. Here is a complete example of creating a ZIP package using edge.js. Also check out the unzip example using edge.js.

Upvotes: -5

Elmer
Elmer

Reputation: 9437

adm-zip

It's a javascript-only library for reading, creating and modifying zip archives in memory.

It looks nice, but it is a little buggy. I had some trouble unzipping a text file.

Upvotes: 1

daraosn
daraosn

Reputation: 117

You can try node-zip npm module.

It ports JSZip to node, to compress/uncompress zip files.

Upvotes: 10

Paul Beusterien
Paul Beusterien

Reputation: 29592

If you only need unzip, node-zipfile looks to be less heavy-weight than node-archive. It definitely has a smaller learning curve.

Upvotes: 1

timoxley
timoxley

Reputation: 5204

If you don't want to use/learn a library, you could use node to control the zip commandline tools by executing child processes

Though I'd recommend learning a library like the one mentioned by Emmerman

Upvotes: 0

Related Questions