49

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

I can't find any node implementation.

KyleMit
  • 30,350
  • 66
  • 462
  • 664
msikora
  • 507
  • 1
  • 4
  • 3

10 Answers10

30

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);
user123444555621
  • 148,182
  • 27
  • 114
  • 126
MateodelNorte
  • 1,282
  • 11
  • 21
29

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();
        }
    });
});
KyleMit
  • 30,350
  • 66
  • 462
  • 664
Eliseo Soto
  • 1,252
  • 2
  • 13
  • 18
  • 2
    Confirming this works on linux no problem, node 0.4.9, with zip installed. Thanks for the code Eliseo, sure saved me some time I bet. – Eliot Sykes Aug 31 '11 at 13:40
  • 1
    Can anybody confirm this will work on Windows without Cygwin? – Ash Blue Jul 28 '12 at 06:58
  • Thanks for this advice. Just a single question - how could I set the archive's name which the browser downloads? Tried to set content-disposition header but this didn't helped. – ecdeveloper Mar 15 '13 at 00:10
  • What is the "app" variable? Is that an http process? – commadelimited Apr 25 '13 at 17:40
  • "app" is an HTTP app created with Express JS – Eliseo Soto Apr 26 '13 at 21:39
  • This answer is pushing the envelope of what I'd call "in node.js" and it will only work when you have these specific binaries installed. Personally, I'm looking for a node.js library that can handle this work without spawning a subprocess. – Stephen Crosby Apr 13 '15 at 20:20
10

You can try node-zip npm module.

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

daraosn
  • 117
  • 1
  • 2
  • Since you look to be the author: What is the purpose of your module? As far as I can see, it's just a wrapper for JsZip: `var fs = require('fs'); var JSZip = require('jszip'); global.JSZip = JSZip; module.exports = function(data, options) { return new JSZip(data, options) };` I have a problem with JsZip in that it's not async, does your module solve the issue? – Eugene Jan 29 '16 at 20:03
  • From the issue tracker https://github.com/daraosn/node-zip/issues/12: "This project is more than 2 years old, by that time I couldn't use JSZip directly on a node application, the same way I'd do it on a front-end app. node-zip just wraps around a global JSZip variable to be used directly in the app and also includes a CLI. So yeah, it's just a port and I'm maintaining it for legacy reasons because lots of projects are using it. Feel free to use JSZip directly." – adabru Oct 21 '19 at 13:33
7

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();
});
Ragnar
  • 4,393
  • 1
  • 27
  • 40
1

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.

Elmer
  • 9,147
  • 2
  • 48
  • 38
  • 2
    Yes it does appear buggy to me as well, crc errors on large files zipped up and checked with 7zip – JohnC Jun 12 '13 at 17:17
  • 2
    This package has [irresponsible dependency versioning](https://github.com/cthackers/adm-zip/issues/121#issuecomment-73559704) and is causing mayhem as we speak. Do not use it. – lazd Feb 09 '15 at 18:31
  • 1
    The comment made by @lazd is now recitified, and adm-zip is not causing mayhem any more... – holroy Mar 03 '15 at 23:31
  • 2
    @holroy that's correct, they removed the offending module and all is well again. – lazd Mar 04 '15 at 19:58
  • adm-zip still has issues in that the compression it uses creates problematic zip archives. See this github issue: https://github.com/cthackers/adm-zip/issues/102 – smb Mar 19 '16 at 14:31
  • For my use case the API and zero-dependency of adm-zip would fit perfectly but sadly it is giving me corrupted files. I'm using jszip instead. – adabru Oct 21 '19 at 15:41
  • I use adm-zip without any issue. – caram Feb 12 '20 at 08:27
1

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

Community
  • 1
  • 1
WaughWaugh
  • 1,012
  • 10
  • 15
1

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');
})();
Todd Price
  • 2,650
  • 1
  • 18
  • 26
1

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

Paul Beusterien
  • 27,542
  • 6
  • 83
  • 139
0

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

timoxley
  • 5,156
  • 3
  • 36
  • 40
-4

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.

Tomasz Janczuk
  • 3,220
  • 21
  • 19