101arrowz / fflate

High performance (de)compression in an 8kB package

Home Page:https://101arrowz.github.io/fflate

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Improve zip documentation

HarelM opened this issue · comments

What can't you do right now?

I can't understand how to create a zip file and how to read one with folders etc.

An optimal solution

Improve the docs.

(How) is this done by other libraries?

I'm using jszip where you can easily add a string and create a file, and browse directories.

I'm also using pako to gunzip, and I would like to use a single library for all my compression and decompression work.
Currently the docs provided here for adding a zip file is partial - what is "chunk1" and "chunk2", how do I iterate over a folder etc...

Here are some of the examples I would like to migrate to this library:
https://github.com/IsraelHikingMap/Site/blob/ba1c6a10ac40d6e429bbeb15778fef8479800a84/IsraelHiking.Web/src/application/services/file.service.ts#L156

https://github.com/IsraelHikingMap/Site/blob/ba1c6a10ac40d6e429bbeb15778fef8479800a84/IsraelHiking.Web/src/application/services/file.service.ts#L245

https://github.com/IsraelHikingMap/Site/blob/ba1c6a10ac40d6e429bbeb15778fef8479800a84/IsraelHiking.Web/src/application/services/file.service.ts#L257

Any help would be appreciated.

To zip a file (like in your first link):

const result = fflate.zipSync({ 'log.txt': fflate.strToU8('some text') });

// convert to a blob if you need
const resultBlob = new Blob([result]);

To unzip (like in your other link):

const zipData = new Uint8Array(await yourBlob.arrayBuffer());
const files = fflate.unzipSync(zipData, {
  filter: file => file.name.startsWith("styles/") && file.name.endsWith(".json")
});

for (const fileName in files) {
  const styleText = fflate.strFromU8(files[fileName]);
  // do whatever you want here
}

If you care about not blocking the main thread, you can replace the zipSync or unzipSync calls with zip or unzip, e.g.

// first example
const result = await new Promise((resolve, reject) => fflate.zip(
   { 'log.txt': fflate.strToU8('some text') },
  (err, result) => err ? reject(err) : resolve(result)
);

// second example
const files = await new Promise((resolve, reject) => fflate.unzip(zipData, {
  filter: file => file.name.startsWith("styles/") && file.name.endsWith(".json")
}, (err, result) => err ? reject(err) : resolve(result)));

For reference, the ZIP documentation is quite thorough; you may have been looking in the wrong place.

From the README (click to expand)
// Note that the asynchronous version (see below) runs in parallel and
// is *much* (up to 3x) faster for larger archives.
const zipped = fflate.zipSync({
  // Directories can be nested structures, as in an actual filesystem
  'dir1': {
    'nested': {
      // You can use Unicode in filenames
      '你好.txt': fflate.strToU8('Hey there!')
    },
    // You can also manually write out a directory path
    'other/tmp.txt': new Uint8Array([97, 98, 99, 100])
  },

  // You can also provide compression options
  'massiveImage.bmp': [aMassiveFile, {
    level: 9,
    mem: 12
  }],
  // PNG is pre-compressed; no need to waste time
  'superTinyFile.png': [aPNGFile, { level: 0 }],

  // Directories take options too
  'exec': [{
    'hello.sh': [fflate.strToU8('echo hello world'), {
      // ZIP only: Set the operating system to Unix
      os: 3,
      // ZIP only: Make this file executable on Unix
      attrs: 0o755 << 16
    }]
  }, {
    // ZIP and GZIP support mtime (defaults to current time)
    mtime: new Date('10/20/2020')
  }]
}, {
  // These options are the defaults for all files, but file-specific
  // options take precedence.
  level: 1,
  // Obfuscate last modified time by default 
  mtime: new Date('1/1/1980')
});

// If you write the zipped data to myzip.zip and unzip, the folder
// structure will be outputted as:

// myzip.zip (original file)
// dir1
// |-> nested
// |   |-> 你好.txt
// |-> other
// |   |-> tmp.txt
// massiveImage.bmp
// superTinyFile.png

// When decompressing, folders are not nested; all filepaths are fully
// written out in the keys. For example, the return value may be:
// { 'nested/directory/structure.txt': Uint8Array(2) [97, 97] }
const decompressed = fflate.unzipSync(zipped, {
  // You may optionally supply a filter for files. By default, all files in a
  // ZIP archive are extracted, but a filter can save resources by telling
  // the library not to decompress certain files
  filter(file) {
    // Don't decompress the massive image or any files larger than 10 MiB
    return file.name != 'massiveImage.bmp' && file.originalSize <= 10_000_000;
  }
});