在 Elixir 中声明 zip 存档内容的最佳方法是啥?

Posted

技术标签:

【中文标题】在 Elixir 中声明 zip 存档内容的最佳方法是啥?【英文标题】:What is the best way to assert the contents of a zip archive in Elixir?在 Elixir 中声明 zip 存档内容的最佳方法是什么? 【发布时间】:2015-07-14 18:24:36 【问题描述】:

目前我在做什么:

    通过压缩文件/目录来测试功能。断言它存在。 使用:zip.t:zip.tt 让它列出zip 文件夹的内容,看看是否符合我的预期。

不知何故,我觉得我错过了一些东西。用:zip.table 测试更好吗?该功能看起来令人困惑。有人可以提供一个如何使用它的例子吗?下面是我得到的输出示例,但我不知道如何将其变成测试? md5sum 是 zip 档案的更好测试吗?

iex(4)> :zip.table('testing.zip')
:ok,
 [:zip_comment, [],
  :zip_file, 'mix.exs',
   :file_info, 930, :regular, :read_write, 2015, 7, 15, 2, 11, 9,
    2015, 7, 15, 2, 11, 9, 2015, 7, 15, 2, 11, 9, 54, 1, 0, 0, 0, 0,
    0, [], 0, 444,
  :zip_file, 'mix.lock',
   :file_info, 332, :regular, :read_write, 2015, 7, 15, 2, 9, 6,
    2015, 7, 15, 2, 9, 6, 2015, 7, 15, 2, 9, 6, 54, 1, 0, 0, 0, 0,
    0, [], 481, 152]

【问题讨论】:

“erlang zip”的第一个 Google 结果显示the zip module from Erlang。在此处提问时,您至少应该表现出一些 的努力。尝试自己开始,然后在遇到问题时提出具体问题。 抱歉,不清楚或没有得到我真正想要的东西。我已经澄清了这个问题。 所以您想编写一个断言 zip 文件内容的测试?您是否也只想断言文件名或压缩文件的内容? 最好是一切,从 zip 中的文件/文件夹到它们的完整性。 我在下面添加了一个答案,但是 TL;DR 我认为围绕压缩和解压缩文件构建单元测试基本上是浪费时间。您基本上是在测试 Erlang zip 库。 【参考方案1】:

来自 Erlang 的 :zip 模块并不容易使用,我会尝试为您分解它。

首先,我们需要zip_file 记录的适当表示,以便 Erlang 能够正确使用它。否则,我们将不得不对具有 lot 元素的元组进行匹配,这只会使我们的代码不必要地混乱。以下模块很大程度上基于the File.Stat implementation from Elixir,将允许我们使用简单的点符号访问那些笨重的元组中的值。

require Record

defmodule Zip.File do
  record = Record.extract(:zip_file, from_lib: "stdlib/include/zip.hrl")
  keys   = :lists.map(&elem(&1, 0), record)
  vals   = :lists.map(&&1, [], nil, keys)
  pairs  = :lists.zip(keys, vals)

  defstruct keys

  def to_record(%Zip.Fileunquote_splicing(pairs)) do
    :zip_file, unquote_splicing(vals)
  end

  def from_record(zip_file)
  def from_record(:zip_file, unquote_splicing(vals)) do
    %Zip.Fileunquote_splicing(pairs)
    |> Map.update!(:info, fn(info) -> File.Stat.from_record(info) end)
  end
end

我们现在可以围绕 Erlang zip 模块构建一个小型包装类。它不包含所有方法,仅包含我们将在此处使用的方法。我还添加了一个 list_files/1 函数,它只返回文件,不包括列表中的目录和 cmets。

defmodule Zip do
  def open(archive) do
    :ok, zip_handle = :zip.zip_open(archive)
    zip_handle
  end

  def close(zip_handle) do
    :zip.zip_close(zip_handle)
  end

  def list_dir(zip_handle) do
    :ok, result = :zip.zip_list_dir(zip_handle)
    result
  end

  def list_files(zip_handle) do
    list_dir(zip_handle)
    |> Enum.drop(1)
    |> Enum.map(&Zip.File.from_record/1)
    |> Enum.filter(&(&1.info.type == :regular))
  end
end

假设我们有以下用于测试的 zip 存档:

cd /tmp
touch foo bar baz
zip archive.zip foo bar baz

现在您可以在 zip 存档中声明文件名:

test "files are in zip" do
  zip = Zip.open('/tmp/archive.zip')
  files = Zip.list_files(zip) |> Enum.map(&(&1.name))
  Zip.close(zip)
  assert files == ['foo', 'bar', 'baz']
end

我将在 zip 存档中留下进一步的操作和断言供您实施,希望这能让您开始。

【讨论】:

【参考方案2】:

您表示要验证 zip 文件及其内容。虽然这部分是 Elixir/Erlang 的问题,但它也超出了这个简单的上下文。这是我的建议:

    创建所有文件的列表并为每个文件创建一个校验和 文件。将其保存在某处。

    压缩整个东西。

    将文件从 zip 解压到其他目录。

    计算解压目录中的文件数——如果是文件数 不一样,测试失败。

    对照步骤 1 中创建的列表检查提取的文件列表。如果文件列表不匹配,则测试失败。

    计算所有文件的校验和。比较校验和 根据步骤 1 中存储的校验和。如果它们不匹配,请测试 失败。

综上所述,这让我觉得这是一个毫无意义的练习,因为基本上你要测试的是 Erlang zip 库。如果 Erlang zip 库中存在缺陷,人们已经大声抱怨了很久,您只需在谷歌上搜索即可发现存在缺陷。

也就是说,虽然你可以为此编写单元测试,但我觉得这是在浪费时间。

【讨论】:

如果您围绕 zip 编写一个包装器函数并添加您自己的功能,它是否仍然有用? 如果您编写一个包装器,那么是的,为包装器功能编写单元测试是有意义的。但这听起来不像你在包装任何东西。

以上是关于在 Elixir 中声明 zip 存档内容的最佳方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

用于创建临时 zip 工件的 Maven 最佳实践

在 Java 中确定 Zip 存档中文件的内容类型

检查 ZIP 存档中内容的文件大小

使用 ZipFile 类从多个文件的 zip 存档中解压缩文件

Android 上的 J7zip - 从存档中提取并列出内容

PHP Zip:提取目录的内容