agu-z/elm-zip/2.1.1

NOTE: the latest version is 3.0.1

Zip

Work with Zip archives.

type Zip

Represents a Zip archive.

An archive is comprised of entries which represent files -that may be compressed- and directories.

Read an archive

fromBytes : Bytes -> Maybe Zip

Read a Zip from Bytes.

If you have an uploaded File of an archive, you can use File.toBytes to read it:

import File exposing (File)
import Task exposing (Task)
import Zip exposing (Zip)


type Msg
    = GotZip (Maybe Zip)


readArchive : File -> Cmd Msg
readArchive file =
    file
        |> File.toBytes
        |> Task.map Zip.fromBytes
        |> Task.perform GotZip

You can also get Bytes from somewhere else, such as an HTTP request, or even from within another archive.

Access the content

Once you have a Zip, you can use it to access its files and directories.

Use the Zip.Entry module to do read their content and metadata.

ls : Zip -> List Entry

List all entries in the archive.

allEntries =
    Zip.ls zip

Files and directories get their own entries.

If you only care about one kind, you can use the Zip.Entry.isDirectory function to filter them:

allFiles =
    zip
        |> Zip.ls
        |> List.filter (not << Entry.isDirectory)
byPath : String -> Zip -> Maybe Entry

Get an entry by its absolute path.

zip |> Zip.byPath "versions/v1.txt"

Nothing is returned if no entry matches the path exactly.

Directory entries are typically stored in the archive with a slash at the end:

zip |> Zip.byPath "versions" == Nothing


zip |> Zip.byPath "versions/" == Just Entry
count : Zip -> Int

Count the number of entries in an archive.

isEmpty : Zip -> Bool

Determine if an archive is empty.

Build an archive

You can alter archives or create your own.

Checkout the Build section of the Zip.Entry module to learn how to make your own entries.

An empty archive with no entries.

From here, you can use insert to add some entries.

fromEntries : List Entry -> Zip

Create an archive from a list of entries.

insert : Entry -> Zip -> Zip

Add a new entry to the archive.

This function replaces entries with the same path. You can conditionally add it by checking existence with the byPath function:

case zip |> Zip.byPath path of
    Nothing ->
        -- Entry does not exist, create and add it
        zip |> Zip.insert (createEntry ())


    Just _ ->
        -- Entry already exists, leave archive as it is
        zip
filter : (Entry -> Bool) -> Zip -> Zip

Only keep entries that pass a given test.

Examples

Remove entries by path:

filter (\entry -> Entry.path entry /= "sample/version.json") zip

Keep all files under 1MB:

filter (\entry -> Entry.extractedSize entry < 1048576) zip

Keep only .txt files:

filter (Entry.path >> String.endsWith ".txt") zip

...and when it's ready

toBytes : Zip -> Bytes

Write a Zip to Bytes.

From here, you can download the archive, upload it to a server, etc.

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        DownloadArchive ->
            ( model
            , model.zip
                |> Zip.toBytes
                |> File.Download.bytes "archive.zip" "application/zip"
            )