# JSZip

Create, read and edit .zip files with Javascript

## How?

var zip = new JSZip(); zip.file("Hello.txt", "Hello World\n"); var img = zip.folder("images"); img.file("smile.gif", imgData, {base64: true}); var content = zip.generate(); location.href="data:application/zip;base64,"+content;

## Why?

1. JavaScript today is capable of generating a lot of data. The easiest way to deliver multiple files to your users is in a zip file. Instead of wasting server resources and bandwidth you can get the client to do it for you.
2. Because it's cool!

## Where?

Download from Github

See also: the test suite

## Tell me more!

### Browser support

Opera | Firefox | Safari | Chrome | Internet Explorer
--- | --- | --- | --- | ---
Yes | Yes | Yes | Yes | Yes
Tested with the latest version | Tested with 3.0 / 3.6 / latest version | Tested with the latest version | Tested with the latest version | Tested with IE 6 / 7 / 8 / 9 / 10

While JSZip should work everywhere, the tricky part is to give the zip file to the user.

### Browser support for data URI scheme with zip

Opera | Firefox | Safari | Chrome | Internet Explorer
--- | --- | --- | --- | ---
7.5+ | 3.0+ | Yes | Yes | No
Filename is "default.zip" | Filename is random alphanumeric with ".part" extension | Filename is "Unknown" (no extension) | Filename is "download.zip" on OSX and Linux, and just "download" on Windows (issue #9) | Only supports data URLs for some content. (May be able to use MHTML?)

### Filename problems

The biggest issue with JSZip is that the filenames are very awkward, Firefox generates filenames such as `a5sZQRsx.zip.part` (see bugs 367231 and 532230), and Safari isn't much better with just `Unknown`. Sadly there is no pure Javascript solution (and working in every browsers) to this. However...

#### Solution-ish: Downloadify

Downloadify uses a small Flash SWF to download files to a user's computer with a filename that you can choose. Doug Neiner has added the `dataType` option to allow you to pass a zip for downloading. Follow the Downloadify demo with the following changes:

    zip = new JSZip();
    zip.file("Hello.", "hello.txt");
    Downloadify.create('downloadify',{
    ...
      data: function(){
        return zip.generate();
      },
    ...
      dataType: 'base64'
    });

#### Other solution-ish: Blob URL

With some recent browsers come a new way to download Blobs (a zip file for example) : blob urls. The download attribute on <a> allows you to give the name of the file. Blob urls start to be widely supported but this attribute is currently only supported in Chrome and Firefox (>= 20). See the example.

    var blob = zip.generate({type:"blob"});
    myLink.href = window.URL.createObjectURL(blob);
    myLink.download = "myFile.zip";

### Usage with Google Gears

Franz Buchinger has written a brilliant tutorial on using JSZip with Google Gears (part 2). If you want to let your Gears users download several files at once I really recommend having a look at some of his examples.

### Reading a zip file from an ajax call

When doing an ajax call to get the binary data, the browser will try to interpret the binary as text, corrupting it. The solution is to set the mimetype to 'text/plain; charset=x-user-defined'. This solution works well in all browsers but IE. If you need IE support, please see what is done in the file test/index.html.

An other solution is to use a modern browser (supporting xhr2) : setting `xhr.type = 'arraybuffer';` will do the trick, JSZip supports ArrayBuffers. Please see the example.

### Reading a local zip file (File API)

JSZip supports (if available in the browser) the File API : reading a local zip file is simple : `new JSZip(readerEvent.target.result);`. Please see the complete example for more details.

## Documentation

#### new JSZip()

Description :
  The default constructor.
Returns :
  A new JSZip.

#### new JSZip(data [,options])

Description :
  Create a new JSZip file and load an existing zip file. See the documentation of `load()` for more details and this for the limitations.
Parameters :
  `data` (same types as `load()`) the content of the zip file to load.
  `options` (Object) options to pass to the `load()` method..
Returns :
  A new JSZip.

    new JSZip(zipDataFromXHR, {base64:false});
    // same as
    var zip = new JSZip();
    zip.load(zipDataFromXHR, {base64:false});

#### file(name)

Description :
  Get a file with the specified name.
Parameters :
  `name` (String) the name of the file.
Returns :
  The file if any, `null` otherwise. The file has the following structure :
  - `name` the absolute path of the file
  - `options` the options of the file. The available options are :
    - `base64`, boolean, cf file(name, data [,options])
    - `binary`, boolean, cf file(name, data [,options])
    - `dir`, boolean, true if this is a directory
    - `date`, date, cf file(name, data [,options])
    - `compression`, String, cf file(name, data [,options])
  - `asText()`, string, the content as an utf8 string (utf8 encoded if necessary).
  - `asBinary()`, string, the content as binary (utf8 decoded if necessary).
  - `asArrayBuffer()`, ArrayBuffer, need a compatible browser.
  - `asUint8Array()`, Uint8Array, need a compatible browser.
  - `asNodeBuffer()`, nodejs Buffer, need nodejs.

    var zip = new JSZip();
    zip.file("file.txt", "content");

    zip.file("file.txt").name // "file.txt"
    zip.file("file.txt").asText() // "content"
    zip.file("file.txt").options.dir // false

    // utf8 example
    var zip = new JSZip(zipFromAjaxWithUTF8);
    zip.file("amount.txt").asText() // "€15"
    zip.file("amount.txt").asArrayBuffer() // an ArrayBuffer containing €15
    zip.file("amount.txt").asUint8Array() // an Uint8Array containing €15

#### file(regex)

Description :
  Search a file in the current folder and subfolders with a regular expression. The regex is tested against the relative filename.
Parameters :
  `regex` (RegExp) the regex to use.
Returns :
  An array of matching files (an empty array if none matched).

    var zip = new JSZip();
    zip.file("file1.txt", "content");
    zip.file("file2.txt", "content");

    zip.file(/file/); // array of size 2

    // example with a relative path :
    var folder = zip.folder("sub");
    folder
      .file("file3.txt", "content")  // relative path from folder : file3.txt
      .file("file4.txt", "content"); // relative path from folder : file4.txt

    folder.file(/file/);  // array of size 2
    folder.file(/^file/); // array of size 2, the relative paths start with file

    // arrays contain objects in the form:
    // {name: "file2.txt", dir: false, asText : function () {...}, ...}

#### file(name, data [,options])

Description :
  Add a file to the zip file.
Parameters :
  `name` (String) the name of the file.
  `data` (String/ArrayBuffer/Uint8Array/Buffer) the content of the file.
  `options` (Object) the options :
  - `base64` (boolean) set to `true` if the data is base64 encoded. For example image data from a `<canvas>` element. Plain text and HTML do not need this option.
  - `binary` (boolean) defaults to `true` if the data is base64 encoded, `false` otherwise. If set to false then UTF-8 characters will be encoded. If the data is an ArrayBuffer or an Uint8Array, this will be set to true.
  - `date` (Date) use it to specify the last modification date. If not set the current date is used.
  - `compression` (String), default null. If set, specifies the file compression method to use. If not, the default file compression is used, cf generate(options).
  - `optimizedBinaryString` (boolean), default false. Set it to true if (and only if) the input is a string and has already been prepared with a 0xFF mask.
Returns :
  A JSZip object, for chaining.

    zip.file("Hello.txt", "Hello World\n");
    zip.file("smile.gif", "R0lGODdhBQAFAIACAAAAAP/eACwAAAAABQAFAAACCIwPkWerClIBADs=", {base64: true});
    zip.file("magic.txt", "U2VjcmV0IGNvZGU=", {base64: true, binary: false});
    zip.file("Xmas.txt", "Ho ho ho !", {date : new Date("December 25, 2007 00:00:01")});
    zip.file("folder/file.txt", "file in folder");

    zip.file("animals.txt", "dog,platypus\n").file("people.txt", "james,sebastian\n");

    // result : Hello.txt, smile.gif, magic.txt, Xmas.txt, animals.txt, people.txt,
    // folder/, folder/file.txt

#### folder(name)

Description :
  Add a directory to the zip file.
Parameters :
  `name` (String) the name of the directory.
Returns :
  a new JSZip (for chaining), with the new folder as root.

    zip.folder("images");
    zip.folder("css").file("style.css", "body {background: #FF0000}");
    // or specify an absolute path (using forward slashes)
    zip.file("css/font.css", "body {font-family: sans-serif}")

    // result : images/, css/, css/style.css, css/font.css

#### folder(regex)

Description :
  Search a subdirectory.
  Search a subdirectory in the current directory with a regular expression. The regex is tested against the relative path.
Parameters :
  `regex` (RegExp) the regex to use.
Returns :
  An array of matching folders (an empty array if none matched).

    var zip = new JSZip();
    zip.folder("home/Pierre/videos");
    zip.folder("home/Pierre/photos");
    zip.folder("home/Jean/videos");
    zip.folder("home/Jean/photos");

    zip.folder(/videos/); // array of size 2

    zip.folder("home/Jean").folder(/^vid/); // array of 1

#### remove(name)

Delete a file or folder.

Description :
  Delete a file or folder (recursively).
Parameters :
  `name` (String) the name of the file/folder to delete.
Returns :
  The current JSZip object.

    var zip = new JSZip();
    zip.file("Hello.txt", "Hello World\n");
    zip.file("temp.txt", "nothing").remove("temp.txt");
    // result : Hello.txt

    zip.folder("css").file("style.css", "body {background: #FF0000}");
    zip.remove("Hello.txt").remove("css");
    //result : empty zip

#### generate(options)

Description :
  Generates the complete zip file.
Parameters :
  `options` (Object) the options to generate the zip file :
  - `base64` (boolean) deprecated, use "type" instead. `false` to get the result as a raw byte string. Default : `true`, encode as base64.
  - `compression` (String) the default file compression method to use. `"STORE"` (no compression) by default, you can use `"DEFLATE"` (include the file jszip-deflate.js) or write your own.
  - `type` (String) the type of zip to return. The possible values are :
    - `base64` (default) : the result will be a string, the binary in a base64 form.
    - `string` : the result will be a string in "binary" form, 1 byte per char.
    - `uint8array` : the result will be a Uint8Array containing the zip. This requires a compatible browser.
    - `arraybuffer` : the result will be a ArrayBuffer containing the zip. This requires a compatible browser.
    - `blob` : the result will be a Blob containing the zip. This requires a compatible browser.
    - `nodebuffer` : the result will be a nodejs Buffer containing the zip. This requires nodejs.
Returns :
  The generated zip file.

HTML5 note : when using type = "uint8array", "arraybuffer" or "blob", be sure to check if the browser supports it (you can use `JSZip.support`). This method will throw an exception otherwise.

    content = zip.generate(); // base64
    location.href="data:application/zip;base64,"+content;

    var blobLink = document.getElementById('blobLink');
    blobLink.download = "hello.zip";
    blobLink.href = window.URL.createObjectURL(
       zip.generate({type:"blob"})
    );

    content = zip.generate({type:"string"});
    for (var c = 0; c < content.length; c++) {
        console.log(content.charCodeAt(c));
        // do other things
    }

#### load(data, options)

Description :
  Read an existing zip and merge the data in the current JSZip object. The implementation is in jszip-load.js, don't forget to include it. This technique has some limitations, see below.
Parameters :
  `data` (String/ArrayBuffer/Uint8Array/Buffer) the zip file
  `options` (Object) the options to load the zip file :
  - `base64` (boolean) `true` if the data is base64 encoded, `false` for binary. Default : `false`.
  - `checkCRC32` (boolean) `true` if the read data should be checked against its CRC32. Default : `false`.
  - `optimizedBinaryString` (boolean), default false. Set it to true if (and only if) the input is a string and has already been prepared with a 0xFF mask.
Returns :
  The current JSZip object.

    var zip = new JSZip();
    zip.load(zipDataFromXHR);

##### Zip features supported by this method

- Compression (`DEFLATE` with jszip-deflate.js)
- zip with data descriptor
- ZIP64
- UTF8 in file name, UTF8 in file content

##### Zip features not (yet) supported

- password protected zip
- multi-volume zip

#### filter(predicate)

Description :
  Filter nested files/folders with the specified function.
Parameters :
  `predicate` (function) the predicate to use : `function (relativePath, file) {...}` It takes 2 arguments : the relative path and the file.
  - `relativePath` (String) The filename and its path, reliatively to the current folder.
  - `file` (Object) The file being tested. Like the result of `file(name)`, the file has the form `{name:"...", options:{...}, asText:function,...}`.
  - Return true if the file should be included, false otherwise.
Returns :
  An array of matching elements.

    var zip = new JSZip().folder("dir");
    zip.file("readme.txt", "content");
    zip.filter(function (relativePath, file){
      // relativePath == "readme.txt"
      // file = {name:"dir/readme.txt",options:{...},asText:function}
      return true/false;
    });

#### JSZip.support

If the browser supports them, JSZip can take advantage of some new features : ArrayBuffer, Blob, Uint8Array. To know if JSZip can use them, you can check the JSZip.support object. It contains the following properties :

- `arraybuffer` : true if JSZip can read and generate ArrayBuffer, false otherwise.
- `uint8array` : true if JSZip can read and generate Uint8Array, false otherwise.
- `blob` : true if JSZip can read and generate Blob, false otherwise.
- `nodebuffer` : true if JSZip can read and generate nodejs Buffer, false otherwise.

### Loading zip files, limitations

#### Not supported features

All the features of zip files are not supported. Classic zip files will work but encrypted zip, multi-volume, etc are not supported and the load() method will throw an `Error`.

#### ZIP64 and 32bit integers

ZIP64 files can be loaded, but only if the zip file is not "too big". ZIP64 uses 64bits integers but Javascript represents all numbers as 64-bit double precision IEEE 754 floating point numbers (see section 8.5). So, we have 53bits for integers and bitwise operations treat everything as 32bits. So if all the 64bits integers can fit into 32 bits integers, everything will be fine. If it's not the case, you will have other problems anyway (see next limitation).

#### Performance issues

An other limitation comes from the browser (and the machine running the browser). A compressed zip file of 10MB is "easily" opened by firefox/chrome/opera/IE10 but will crash older IE. Also keep in mind that strings in javascript are encoded in UTF-16 : a 10MB ascii text file will take 20MB of memory.

If you're having performance issues, please consider the following :

- Don't use IE < 10. Everything is better with WebGL support.
- If you load the file from an ajax call, ask your XHR an ArrayBuffer. Loading a string is asking for troubles.
- If you want to get the content of an ASCII file as a string, consider using `asBinary()` instead of `asText()`. The transformation "binary string" -> "utf string" is a consuming process.

#### The output zip will differ from the input zip

Reading and generating a zip file won't give you back the same file. Some data are discarded (file metadata) and other are added (subfolders).

## Changelog

### 1.0.1 2013-03-04

- Fixed an issue when generating a compressed zip file with empty files or folders, see #33.
- With bad data (`null` or `undefined`), asText/asBinary/asUint8Array/asArrayBuffer methods now return an empty string, see #36.

### 1.0.0 2013-02-14

First release after a long period without version.

## Migrating Guide

### From 1.0.x to ?

- `JSZipBase64` has been renamed to `JSZip.base64`.
- The `data` attribute doesn't exist anymore : use the getters `asText()`, `asBinary()`, etc
- The compression/decompression methods now give their input type with the `compressInputType` and `uncompressInputType`attributes.``

Example for the data attribute :

    // before
    zip.file("test.txt").data;
    zip.files["test.txt"].data;

    // after
    zip.file("test.txt").asText();
    zip.files["test.txt"].asText();

## Anything else?

### License

MIT license or GPLv3

### Version

1.0.1

See the migrating guide when updating the library !

### Todo

- Set correct version needed to extract
- Set correct version made by
- Set internal and external file attributes in central directory
- Allow setting of attributes/other info in `add()` options object
- Look into using MHTML for IE

### Who?

Stuart Knightley, with contributions from:

- Franz Buchinger
- António Afonso
- David Duponchel
- yiminghe

### Contact and bugs

- Issue tracker
- Email me