{"id":16702231,"url":"https://github.com/akash-akya/unzip","last_synced_at":"2026-02-20T00:31:16.632Z","repository":{"id":39852785,"uuid":"235632518","full_name":"akash-akya/unzip","owner":"akash-akya","description":"Module to get files out of a zip","archived":false,"fork":false,"pushed_at":"2025-10-29T18:26:26.000Z","size":4601,"stargazers_count":21,"open_issues_count":0,"forks_count":10,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-11-07T02:14:36.745Z","etag":null,"topics":["elixir","remote","s3","sftp","unzip","zip","zip64"],"latest_commit_sha":null,"homepage":"","language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/akash-akya.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"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,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2020-01-22T17:58:55.000Z","updated_at":"2025-10-29T18:25:06.000Z","dependencies_parsed_at":"2023-11-18T00:13:20.590Z","dependency_job_id":"5af1a223-68c4-49a2-85df-60b8c5bdcfa4","html_url":"https://github.com/akash-akya/unzip","commit_stats":{"total_commits":52,"total_committers":4,"mean_commits":13.0,"dds":0.05769230769230771,"last_synced_commit":"f05794b0dec9961fad392a4eea31e0b18a9d5986"},"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"purl":"pkg:github/akash-akya/unzip","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/akash-akya%2Funzip","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/akash-akya%2Funzip/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/akash-akya%2Funzip/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/akash-akya%2Funzip/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/akash-akya","download_url":"https://codeload.github.com/akash-akya/unzip/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/akash-akya%2Funzip/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29637408,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-19T22:32:43.237Z","status":"ssl_error","status_checked_at":"2026-02-19T22:32:38.330Z","response_time":117,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["elixir","remote","s3","sftp","unzip","zip","zip64"],"created_at":"2024-10-12T18:47:17.696Z","updated_at":"2026-02-20T00:31:16.617Z","avatar_url":"https://github.com/akash-akya.png","language":"Elixir","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Unzip\n\n[![CI](https://github.com/akash-akya/unzip/actions/workflows/ci.yml/badge.svg)](https://github.com/akash-akya/unzip/actions/workflows/ci.yml)\n[![Hex.pm](https://img.shields.io/hexpm/v/unzip.svg)](https://hex.pm/packages/unzip)\n[![docs](https://img.shields.io/badge/docs-hexpm-blue.svg)](https://hexdocs.pm/unzip/)\n\nElixir library to stream zip file contents. Works with remote files. Supports Zip64.\n\n## Overview\n\nUnzip tries to solve problem of unzipping files from different types of storage (Aws S3, SFTP server, in-memory etc). It separates type of storage from zip implementation. Unzip can stream zip contents from any type of storage which implements `Unzip.FileAccess` protocol. You can selectively stream files from zip without reading the complete zip. This saves bandwidth and decompression time if you only need few files from the zip. For example, if a zip file contains 100 files and we only want one file then `Unzip` access only that particular file\n\n## Installation\n\n```elixir\ndef deps do\n  [\n    {:unzip, \"~\u003e x.x.x\"}\n  ]\nend\n```\n\n## Usage\n\n```elixir\n# Unzip.LocalFile implements Unzip.FileAccess\nzip_file = Unzip.LocalFile.open(\"foo/bar.zip\")\n\n# `new` reads list of files by reading central directory found at the end of the zip\n{:ok, unzip} = Unzip.new(zip_file)\n\n# Alternatively if you have the zip file in memory as binary you can\n# directly pass it to `Unzip.new(binary)` to unzip\n#\n# {:ok, unzip} = Unzip.new(\u003c\u003cbinary\u003e\u003e)\n\n# returns list of files along with metadata\nfile_entries = Unzip.list_entries(unzip)\n\n# returns decompressed file stream\nstream = Unzip.file_stream!(unzip, \"baz.png\")\n\n# if you want to read the whole file as binary\n#\n# file_content = Enum.into(stream, \u003c\u003c\u003e\u003e, \u0026IO.iodata_to_binary/1)\n```\n\nSupports STORED and DEFLATE compression methods. Supports zip64 specification.\n\n## Sample implementations of `Unzip.FileAccess` protocol\n\nFor Aws S3 using [ExAws](https://hexdocs.pm/ex_aws/ExAws.html)\n\n```elixir\ndefmodule Unzip.S3File do\n  defstruct [:path, :bucket, :s3_config]\n  alias __MODULE__\n\n  def new(path, bucket, s3_config) do\n    %S3File{path: path, bucket: bucket, s3_config: s3_config}\n  end\nend\n\ndefimpl Unzip.FileAccess, for: Unzip.S3File do\n  alias ExAws.S3\n\n  def size(file) do\n    %{headers: headers} = S3.head_object(file.bucket, file.path) |\u003e ExAws.request!(file.s3_config)\n\n    size =\n      headers\n      |\u003e Enum.find(fn {k, _} -\u003e String.downcase(k) == \"content-length\" end)\n      |\u003e elem(1)\n      |\u003e String.to_integer()\n\n    {:ok, size}\n  end\n\n  def pread(file, offset, length) do\n    {_, chunk} =\n      S3.Download.get_chunk(\n        %S3.Download{bucket: file.bucket, path: file.path, dest: nil},\n        %{start_byte: offset, end_byte: offset + length - 1},\n        file.s3_config\n      )\n\n    {:ok, chunk}\n  end\nend\n\n\n# Using S3File\n\naws_s3_config = ExAws.Config.new(:s3,\n  access_key_id: [\"key_id\", :instance_role],\n  secret_access_key: [\"key\", :instance_role]\n)\n\nfile = Unzip.S3File.new(\"pets.zip\", \"pics\", aws_s3_config)\n{:ok, unzip} = Unzip.new(file)\nfiles = Unzip.list_entries(unzip)\n\nUnzip.file_stream!(unzip, \"cats/kitty.png\")\n|\u003e Stream.into(File.stream!(\"kitty.png\"))\n|\u003e Stream.run()\n\n```\n\nFor zip file in SFTP server\n\n```elixir\ndefmodule Unzip.SftpFile do\n  defstruct [:channel_pid, :connection_ref, :handle, :file_path]\n  alias __MODULE__\n\n  def new(host, port, sftp_opts, file_path) do\n    :ok = :ssh.start()\n\n    {:ok, channel_pid, connection_ref} =\n      :ssh_sftp.start_channel(to_charlist(host), port, sftp_opts)\n\n    {:ok, handle} = :ssh_sftp.open(channel_pid, file_path, [:read, :raw, :binary])\n\n    %SftpFile{\n      channel_pid: channel_pid,\n      connection_ref: connection_ref,\n      handle: handle,\n      file_path: file_path\n    }\n  end\n\n  def close(file) do\n    :ssh_sftp.close(file.channel_pid, file.handle)\n    :ssh_sftp.stop_channel(file.channel_pid)\n    :ssh.close(file.connection_ref)\n    :ok\n  end\nend\n\ndefimpl Unzip.FileAccess, for: Unzip.SftpFile do\n  def size(file) do\n    {:ok, file_info} = :ssh_sftp.read_file_info(file.channel_pid, file.file_path)\n    {:ok, elem(file_info, 1)}\n  end\n\n  def pread(file, offset, length) do\n    :ssh_sftp.pread(file.channel_pid, file.handle, offset, length)\n  end\nend\n\n\n# Using SftpFile\n\nsftp_opts = [\n  user_interaction: false,\n  silently_accept_hosts: true,\n  rekey_limit: 1_000_000_000_000,\n  user: 'user',\n  password: 'password'\n]\n\nfile = Unzip.SftpFile.new('127.0.0.1', 22, sftp_opts, '/home/user/pics.zip')\n\ntry do\n  {:ok, unzip} = Unzip.new(file)\n  files = Unzip.list_entries(unzip)\n\n  Unzip.file_stream!(unzip, \"cats/kitty.png\")\n  |\u003e Stream.into(File.stream!(\"kitty.png\"))\n  |\u003e Stream.run()\nafter\n  Unzip.SftpFile.close(file)\nend\n\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fakash-akya%2Funzip","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fakash-akya%2Funzip","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fakash-akya%2Funzip/lists"}