6

我知道如何在 Elixir 中以写入模式打开一个 zip 文件:

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

但在此之后,如果我有一个目录/home/lowks/big_files,我该如何将它写入file

4

2 回答 2

10

如果您对 zip 文件进行操作,则需要使用:zip.extract('foo.zip'), 和:zip.create(name, [{'foo', file1data}, file2path, ...]).

:zip.create接受一个名称和一个可以包含两个选项之一的列表:

  1. 包含文件名和要压缩的二进制数据的元组。
  2. 要压缩的文件的路径。

:zip.extract可以采用文件路径,也可以采用表示 zip 存档的二进制数据(可能来自File.open对 zip 进行操作)。

您可以执行以下操作来获取路径中的文件列表并将它们压缩:

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)
于 2014-03-22T01:24:14.013 回答
2

这是一个相当不错的答案,但这里有一个更好的答案,它支持从某个位置递归地将目录添加到 zip 中。

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

这里是 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

一句警告;我不会将它用于任何非常大的东西,它可能会在这里使用 File.read 破坏一切。我不确定如何使用文件句柄,但我认为这是可能的。随意改进和回馈;-)

我还缓存了 zip 文件,因此它不会每次都执行。

于 2017-06-24T07:44:00.850 回答