我知道如何在 Elixir 中以写入模式打开一个 zip 文件:
file = File.open("myzip.zip", [:write, :compressed])
但在此之后,如果我有一个目录/home/lowks/big_files
,我该如何将它写入file
?
我知道如何在 Elixir 中以写入模式打开一个 zip 文件:
file = File.open("myzip.zip", [:write, :compressed])
但在此之后,如果我有一个目录/home/lowks/big_files
,我该如何将它写入file
?
如果您对 zip 文件进行操作,则需要使用:zip.extract('foo.zip')
, 和:zip.create(name, [{'foo', file1data}, file2path, ...])
.
:zip.create
接受一个名称和一个可以包含两个选项之一的列表:
: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)
这是一个相当不错的答案,但这里有一个更好的答案,它支持从某个位置递归地将目录添加到 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 文件,因此它不会每次都执行。