Muhammad Lukman Low
Muhammad Lukman Low

Reputation: 8533

How to compress a directory in Elixir?

I know how to open up a zip file in write mode in Elixir:

file = File.open("myzip.zip", [:write, :compressed])

but after this, say if I have a directory /home/lowks/big_files, how do I write this into file ?

Upvotes: 6

Views: 3352

Answers (2)

pip
pip

Reputation: 453

This is a fairly good answer, but here is a better one that supports recursively adding directories to the zip from a location.

  files = create_files_list(path)
  :zip.create(to_charlist(zip_file_path), files)

And here is create_files_list:

  defp create_files_list(path) do
    create_files_list(File.ls!(path), path)
  end
  defp create_files_list(paths, path) do
    create_files_list(paths, path, path)
  end
  defp create_files_list(paths, path, base_path) do
    Enum.reduce(paths, [],
      fn(filename, acc) ->
        filename_path = Path.join(path, filename)
        if File.dir?(filename_path) do
          acc ++ create_files_list(File.ls!(filename_path), filename_path, base_path)
        else
          filenm = 
            if base_path, 
              do: String.replace_leading(filename_path, base_path, ""), 
              else: filename_path
          [{String.to_char_list(filenm), File.read!(filename_path)} | acc]
        end
      end
    )
  end

A word of warning; I'm not using this for anything very large, it might break everything by using File.read here. I'm not sure how to use File handles but I think it's possible. Feel free to improve and contribute back ;-)

I also cache the zip file so it isn't executed every time.

Upvotes: 2

bitwalker
bitwalker

Reputation: 9261

If you are operating on zip files, you'll need to use :zip.extract('foo.zip'), and :zip.create(name, [{'foo', file1data}, file2path, ...]).

:zip.create takes a name, and a list which can contain either of two options:

  1. A tuple containing a file name, and binary data to zip.
  2. A path to a file to zip.

:zip.extract can either take a path to a file, or binary data representing the zip archive (perhaps from doing File.open on a zip).

You can do something like the following to take a list of files in a path and zip them up:

files = File.ls!(path)
        |> Enum.map(fn filename -> Path.join(path, filename) end)
        |> Enum.map(&String.to_char_list!/1)

:zip.create('foo.zip', files)

Upvotes: 10

Related Questions