{"id":13472189,"url":"https://github.com/antelle/node-stream-zip","last_synced_at":"2025-05-15T02:09:31.874Z","repository":{"id":27652208,"uuid":"31137468","full_name":"antelle/node-stream-zip","owner":"antelle","description":"node.js library for fast reading of large ZIPs","archived":false,"fork":false,"pushed_at":"2023-11-12T17:38:09.000Z","size":774,"stargazers_count":461,"open_issues_count":18,"forks_count":65,"subscribers_count":11,"default_branch":"master","last_synced_at":"2025-05-05T06:39:51.393Z","etag":null,"topics":["javascript","nodejs","zip","zip64"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/antelle.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null},"funding":{"github":"antelle","patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"custom":null}},"created_at":"2015-02-21T19:20:02.000Z","updated_at":"2025-05-02T19:05:03.000Z","dependencies_parsed_at":"2024-03-13T00:32:12.308Z","dependency_job_id":"511614db-f9ea-4fdf-936b-86ec7c4d52cd","html_url":"https://github.com/antelle/node-stream-zip","commit_stats":{"total_commits":132,"total_committers":14,"mean_commits":9.428571428571429,"dds":"0.18181818181818177","last_synced_commit":"7c5d50393418b261668b0dd4c8d9ccaa9ac913ce"},"previous_names":[],"tags_count":47,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/antelle%2Fnode-stream-zip","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/antelle%2Fnode-stream-zip/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/antelle%2Fnode-stream-zip/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/antelle%2Fnode-stream-zip/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/antelle","download_url":"https://codeload.github.com/antelle/node-stream-zip/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252865704,"owners_count":21816307,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["javascript","nodejs","zip","zip64"],"created_at":"2024-07-31T16:00:52.750Z","updated_at":"2025-05-15T02:09:31.852Z","avatar_url":"https://github.com/antelle.png","language":"JavaScript","readme":"# node-stream-zip ![CI Checks](https://github.com/antelle/node-stream-zip/workflows/CI%20Checks/badge.svg)\n\nnode.js library for reading and extraction of ZIP archives.  \nFeatures:\n\n- it never loads entire archive into memory, everything is read by chunks\n- large archives support\n- all operations are non-blocking, no sync i/o\n- fast initialization\n- no dependencies, no binary addons\n- decompression with built-in zlib module\n- deflate, sfx, macosx/windows built-in archives\n- ZIP64 support\n\n## Installation\n\n```sh\nnpm i node-stream-zip\n```\n\n## Usage\n\nThere are two APIs provided:\n1. [promise-based / async](#async-api) \n2. [callbacks](#callback-api)\n\nIt's recommended to use the new, promise API, however the legacy callback API \nmay be more flexible for certain operations.\n\n### Async API\n\nOpen a zip file\n```javascript\nconst StreamZip = require('node-stream-zip');\nconst zip = new StreamZip.async({ file: 'archive.zip' });\n```\n\nStream one entry to stdout\n```javascript\nconst stm = await zip.stream('path/inside/zip.txt');\nstm.pipe(process.stdout);\nstm.on('end', () =\u003e zip.close());\n```\n\nRead a file as buffer\n```javascript\nconst data = await zip.entryData('path/inside/zip.txt');\nawait zip.close();\n```\n\nExtract one file to disk\n```javascript\nawait zip.extract('path/inside/zip.txt', './extracted.txt');\nawait zip.close();\n```\n\nList entries\n```javascript\nconst entriesCount = await zip.entriesCount;\nconsole.log(`Entries read: ${entriesCount}`);\n\nconst entries = await zip.entries();\nfor (const entry of Object.values(entries)) {\n    const desc = entry.isDirectory ? 'directory' : `${entry.size} bytes`;\n    console.log(`Entry ${entry.name}: ${desc}`);\n}\n\n// Do not forget to close the file once you're done\nawait zip.close();\n```\n\nExtract a folder from archive to disk\n```javascript\nfs.mkdirSync('extracted');\nawait zip.extract('path/inside/zip/', './extracted');\nawait zip.close();\n```\n\nExtract everything\n```javascript\nfs.mkdirSync('extracted');\nconst count = await zip.extract(null, './extracted');\nconsole.log(`Extracted ${count} entries`);\nawait zip.close();\n```\n\nWhen extracting a folder, you can listen to `extract` event\n```javascript\nzip.on('extract', (entry, file) =\u003e {\n    console.log(`Extracted ${entry.name} to ${file}`);\n});\n```\n\n`entry` event is generated for every entry during loading\n```javascript\nzip.on('entry', entry =\u003e {\n    // you can already stream this entry,\n    // without waiting until all entry descriptions are read (suitable for very large archives)\n    console.log(`Read entry ${entry.name}`);\n});\n```\n\n### Callback API\n\nOpen a zip file\n```javascript\nconst StreamZip = require('node-stream-zip');\nconst zip = new StreamZip({ file: 'archive.zip' });\n\n// Handle errors\nzip.on('error', err =\u003e { /*...*/ });\n```\n\nList entries\n```javascript\nzip.on('ready', () =\u003e {\n    console.log('Entries read: ' + zip.entriesCount);\n    for (const entry of Object.values(zip.entries())) {\n        const desc = entry.isDirectory ? 'directory' : `${entry.size} bytes`;\n        console.log(`Entry ${entry.name}: ${desc}`);\n    }\n    // Do not forget to close the file once you're done\n    zip.close();\n});\n```\n\nStream one entry to stdout\n```javascript\nzip.on('ready', () =\u003e {\n    zip.stream('path/inside/zip.txt', (err, stm) =\u003e {\n        stm.pipe(process.stdout);\n        stm.on('end', () =\u003e zip.close());\n    });\n});\n```\n\nExtract one file to disk\n```javascript\nzip.on('ready', () =\u003e {\n    zip.extract('path/inside/zip.txt', './extracted.txt', err =\u003e {\n        console.log(err ? 'Extract error' : 'Extracted');\n        zip.close();\n    });\n});\n```\n\nExtract a folder from archive to disk\n```javascript\nzip.on('ready', () =\u003e {\n    fs.mkdirSync('extracted');\n    zip.extract('path/inside/zip/', './extracted', err =\u003e {\n        console.log(err ? 'Extract error' : 'Extracted');\n        zip.close();\n    });\n});\n```\n\nExtract everything\n```javascript\nzip.on('ready', () =\u003e {\n    fs.mkdirSync('extracted');\n    zip.extract(null, './extracted', (err, count) =\u003e {\n        console.log(err ? 'Extract error' : `Extracted ${count} entries`);\n        zip.close();\n    });\n});\n```\n\nRead a file as buffer in sync way\n```javascript\nzip.on('ready', () =\u003e {\n    const data = zip.entryDataSync('path/inside/zip.txt');\n    zip.close();\n});\n```\n\nWhen extracting a folder, you can listen to `extract` event\n```javascript\nzip.on('extract', (entry, file) =\u003e {\n    console.log(`Extracted ${entry.name} to ${file}`);\n});\n```\n\n`entry` event is generated for every entry during loading\n```javascript\nzip.on('entry', entry =\u003e {\n    // you can already stream this entry,\n    // without waiting until all entry descriptions are read (suitable for very large archives)\n    console.log(`Read entry ${entry.name}`);\n});\n```\n\n## Options\n\nYou can pass these options to the constructor\n- `storeEntries: true` - you will be able to work with entries inside zip archive, otherwise the only way to access them is `entry` event\n- `skipEntryNameValidation: true` - by default, entry name is checked for malicious characters, like `../` or `c:\\123`, pass this flag to disable validation errors\n- `nameEncoding: 'utf8'` - encoding used to decode file names, UTF8 by default\n\n## Methods\n\n- `zip.entries()` - get all entries description\n- `zip.entry(name)` - get entry description by name\n- `zip.stream(entry, function(err, stm) { })` - get entry data reader stream\n- `zip.entryDataSync(entry)` - get entry data in sync way\n- `zip.close()` - cleanup after all entries have been read, streamed, extracted, and you don't need the archive\n\n## Building\n\nThe project doesn't require building. To run unit tests with [nodeunit](https://github.com/caolan/nodeunit):  \n```sh\nnpm test\n```\n\n## Known issues\n\n- [utf8](https://github.com/rubyzip/rubyzip/wiki/Files-with-non-ascii-filenames) file names\n\n## Out of scope\n\n- AES encrypted files: the library will throw an error if you try to open it\n\n## Contributors\n\nZIP parsing code has been partially forked from [cthackers/adm-zip](https://github.com/cthackers/adm-zip) (MIT license).\n","funding_links":["https://github.com/sponsors/antelle"],"categories":["JavaScript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fantelle%2Fnode-stream-zip","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fantelle%2Fnode-stream-zip","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fantelle%2Fnode-stream-zip/lists"}