压缩

描述

创建压缩文件。

basedir 属性是压缩的参考目录。

请注意,文件权限不会存储在生成的压缩文件中。

可以细化要压缩的文件集。这可以通过 includesincludesfileexcludesexcludesfiledefaultexcludes 属性来完成。使用 includesincludesfile 属性,您可以使用模式指定要包含的文件。excludeexcludesfile 属性用于指定要排除的文件。这也是使用模式完成的。最后,使用 defaultexcludes 属性,您可以指定是否要使用默认排除项。有关如何包含/排除文件以及如何编写模式的信息,请参见有关 基于目录的任务 的部分。

此任务形成一个隐式的 文件集,并支持大多数 <fileset> 的属性(dir 变为 basedir),以及嵌套的 <include><exclude><patternset> 元素。

或者,您可以在其中放置嵌套的文件集,或引用文件集。在这种情况下,basedir 是可选的;只有在设置了 basedir 时才会使用隐式文件集。您可以混合使用隐式文件集(设置了 basedir,以及可选属性,如 includes,以及可选子元素,如 <include>);显式嵌套的 <fileset> 元素,只要至少指定了一个文件集。压缩文件将只反映每个文件集内文件的相对路径。压缩任务及其派生任务知道一种名为 zipfileset 的特殊文件集形式,它具有额外的属性(在下面描述)。

压缩任务还支持将多个压缩文件合并到压缩文件中。这可以通过任何嵌套文件集的 src 属性或使用特殊的嵌套文件集 zipgroupfileset 来实现。

update 参数控制如果压缩文件已存在会发生什么。当设置为 yes 时,压缩文件将使用指定的文件进行更新。(添加新文件;用新版本替换旧文件。)当设置为 no(默认值)时,如果要添加到存档的任何文件都比存档中的条目更新,则会覆盖压缩文件。请注意,压缩文件以 2 秒的粒度存储文件修改时间。如果文件比存档中的条目晚不到 2 秒,Apache Ant 不会认为它更新。

whenempty 参数控制当没有文件匹配时会发生什么。如果为 skip(默认值),则不会创建压缩文件,并且会发出警告。如果为 fail,则不会创建压缩文件,并且构建将因错误而停止。如果为 create,则会创建一个空的压缩文件(明确为零个条目),符合的压缩文件操作工具应该识别它。

此任务现在将使用默认的 JVM 字符编码来表示文件名——这与命令行压缩工具一致,但如果您尝试从 Java 中打开它们并且文件名包含非 US-ASCII 字符,则会导致问题。使用 encoding 属性并将其设置为 UTF8 以创建可以安全地由 Java 读取的压缩文件。有关更完整的讨论,请参见 下面

自 Ant 1.5.2 起<zip> 可以将 Unix 权限存储在存档中(有关 filemodedirmode 属性的描述,请参见 <zipfileset>)。不幸的是,没有便携式方法来存储这些权限。Ant 使用 Info-Zip 实现的 zipunzip 命令中使用的算法——这些是许多 Unix(类 Unix)系统中 zipunzip 的默认版本。

请注意,压缩格式允许在单个存档中存在多个具有相同完全限定名称的文件。这已被记录为会导致对毫无戒心的用户造成各种问题。如果您希望避免这种行为,您必须将 duplicate 属性设置为除其默认值 add 之外的值。

另请注意,不同的压缩工具在应用文件的时区偏移计算方面对时间戳的处理方式不同。一些压缩库将时间戳存储为从文件系统读取的时间戳,而另一些库将在读取和写入文件时修改时间戳,以使所有时间戳使用相同的时区。由一个库创建的压缩存档在由另一个库解压缩时可能会解压缩出具有“错误时间戳”的文件。

Ant 的压缩类使用与 InfoZIP 工具和 zlib 相同的算法(时间戳会进行调整),Windows 的“压缩文件夹”功能和 WinZIP 不会更改时间戳。这意味着,对 Windows 的压缩文件夹功能创建的文件使用 unzip 任务可能会创建具有“错误”时间戳的文件,如果您使用 Windows 的功能解压缩 Ant 生成的压缩存档,也是如此。

参数

属性 描述 必需
destfile 要创建的压缩文件。 两者之一
zipfile 已弃用 destfile 的旧名称。
basedir 压缩文件的目录。
compress 不仅存储数据,还要压缩它们。除非您将 keepcompression 属性设置为 false,否则这将应用于整个存档,而不仅仅是您在更新时添加的文件。 否;默认为 true
keepcompression 对于来自现有存档的条目(如嵌套的 zipfileset 或更新存档时),保持原始压缩方式,而不是使用 compress 属性。自 Ant 1.6 起 否;默认为 false
encoding 压缩文件内文件名使用的字符编码。有关可能值的列表,请参见 支持的编码 否;默认为默认的 JVM 字符编码
filesonly 仅存储文件条目。 否;默认为 false
includes 必须包含的文件模式的逗号或空格分隔列表。 否;默认为全部 (**)
includesfile 文件的名称。此文件的每一行都被视为一个包含模式。
excludes 必须排除的文件模式的逗号或空格分隔列表。 否;默认为默认排除项,如果 defaultexcludesno,则为无
excludesfile 文件的名称。此文件的每一行都被视为一个排除模式。
defaultexcludes 指示是否应使用默认排除项 (yes|no)。 否;默认为 yes
update 指示如果目标文件已存在,是否更新或覆盖它。 否;默认为 false
whenempty 当没有文件匹配时的行为。有效值为 failskipcreate 否;默认为 skip
duplicate 找到重复文件时的行为。有效值为 addpreservefail 否;默认为 add
roundup 文件修改时间是否将四舍五入到下一个偶数秒。
压缩存档以 2 秒的粒度存储文件修改时间,因此时间将四舍五入或舍入。如果您舍入,则每次重新运行任务时,存档似乎总是过时,因此默认值为四舍五入。四舍五入可能会导致其他类型的问题,例如 Web 存档中的 JSP 似乎比预编译页面略微更新,从而使预编译变得毫无用处。自 Ant 1.6.2 起
否;默认为 true
comment 要存储在存档中的注释。自 Ant 1.6.3 起
level 执行文件压缩的非默认级别。有效值范围从 0(无压缩/最快)到 9(最大压缩/最慢)。自 Ant 1.7 起
preserve0permissions 更新存档或添加来自不同存档的条目时,Ant 将假设 Unix 权限值为 0(没有人被允许对文件/目录执行任何操作)意味着权限根本没有存储,而不是实际权限,并将改为应用其自己的默认值。
如果您确实要保留原始权限字段,请将此属性设置为 true自 Ant 1.8.0 起
否;默认为 false
useLanguageEncodingFlag 如果编码为 UTF-8,是否设置语言编码标志。如果编码不是 UTF-8,此设置没有任何影响。自 Ant 1.8.0 起
另请参见 下面的讨论
否;默认为 true
createUnicodeExtraFields 是否创建 Unicode 额外字段以在条目的元数据中第二次存储文件名。
可能的值为 neveralwaysnot-encodeable,如果文件名无法使用指定的编码进行编码,则只会添加 Unicode 额外字段。自 Ant 1.8.0 起
另请参见 下面的讨论
否;默认为 never
fallbacktoUTF8 如果文件名无法使用指定的编码进行编码,是否使用 UTF-8 和语言编码标志而不是指定的编码。自 Ant 1.8.0 起
另请参见 下面的讨论
否;默认为 false
zip64Mode 何时对条目使用 Zip64 扩展。可能的值为 neveralwaysas-needed自 Ant 1.9.1 起
另请参见 下面的讨论
否;默认为 as-needed
modificationtime 将所有存储的文件修改时间设置为给定时间。这可以是解释为自 1970-01-01T00:00:00Z 以来的毫秒数,也可以是可解析为带有时区可选的 ISO 8601 时间戳的字符串。自 Ant 1.10.2 起

文件名的编码

传统上,压缩存档格式使用 CodePage 437 作为文件名编码,这对于许多国际字符集来说是不够的。

随着时间的推移,不同的存档程序选择了不同的方法来解决此限制——例如,java.util.zip 包简单地使用 UTF-8 作为其编码。

自 Ant 1.4 起,Ant 一直提供 zipunzip 任务的 encoding 属性作为一种方法来明确指定要使用(或期望)的编码。它默认为 zip 的默认 JVM 字符编码,以及 jar 和其他类似 jar 的任务(warear 等)以及 unzip 任务系列的 UTF-8。

最新版本的压缩规范引入了名为 语言编码标志 的内容,它可以用来表示文件名已使用 UTF-8 编码。自 Ant 1.8.0 起,由 Ant 编写的所有压缩、jar 和类似存档都将设置此标志,如果编码已设置为 UTF-8。我们与现有存档程序的互操作性测试没有显示任何不良影响(事实上,大多数存档程序到目前为止都忽略了此标志),但是如果您遇到问题,可以通过将 zip 任务上的 useLanguageEncodingFlag 属性设置为 false 来关闭 语言编码标志

unzip 任务(以及类似的任务)将识别语言编码标志,如果找到它,则会忽略任务上设置的编码。

InfoZIP 开发人员引入了新的压缩额外字段,可用于将额外的 UTF-8 编码文件名添加到条目的元数据中。大多数存档程序忽略这些额外字段。自 Ant 1.8.0 起zip 任务系列支持一个选项 createUnicodeExtraFields,它使 Ant 编写这些额外字段,要么针对所有条目 (always),要么只针对那些其名称无法使用指定的编码 (not-encodeable) 进行编码,它默认为 never,因为额外字段会创建更大的存档。

zipfallbackToUTF8 属性可用于创建在大多数情况下使用指定编码的存档,但对于无法使用指定编码进行编码的文件名,则使用 UTF-8 和语言编码标志。

默认情况下,unzip 任务会识别 Unicode 扩展字段并从其中读取文件名信息,除非您将可选属性 scanForUnicodeExtraFields 设置为 false

互操作性建议

标志的最佳设置取决于您期望作为 ZIP 存档的消费者/生产者的存档器。以下是可能被每个工具的更高版本取代的一些测试结果。

那么,该怎么做呢?

如果您正在创建 jar,那么 java.util.zip 是您的主要消费者。我们建议您将编码设置为 UTF-8 并保持语言编码标志启用。该标志在 Java 7 之前不会对 java.util.zip 有帮助或造成伤害,但支持它的存档器将显示正确的文件名。

为了最大限度地提高互操作性,最好将编码设置为 UTF-8,启用语言编码标志并在写入 ZIP 时创建 Unicode 扩展字段。此类存档应该能够被 java.util.zip、7Zip、WinZIP、PKWARE 工具以及大多数 InfoZIP 工具正确提取。但是,它们将无法与 Windows 的“压缩文件夹”功能一起使用,并且比没有 Unicode 扩展字段的存档更大。

如果 Windows 的“压缩文件夹”是您的主要消费者,那么最好的选择是显式地将编码设置为目标平台。您可能希望启用 Unicode 扩展字段的创建,以便支持它们的工具能够正确提取文件名。

Zip64 扩展

Zip64 扩展提供了一种方法来创建大于 4 GB 或包含超过 65535 个条目(或使用 ZIP 扩展字段机制添加大于 4 GB 的单个条目)的存档。大多数现代 ZIP 实现都支持这些扩展。

当 Ant 将压缩条目写入它创建的存档时,它在写入之前不知道条目的压缩大小。不幸的是,必须在写入条目的内容之前做出是否写入 Zip64 扩展字段的决定。

Ant 1.9.0 引入了对 Zip64 扩展的支持,但没有提供对其使用的任何控制。从 Ant 1.9.1 开始,在 zip 任务系列中添加了一个新的 zip64mode 属性。它支持三个值

as-needed 提供了一个很好的折衷方案,如果您不知道您的存档是否会超过传统 zip 文件的限制,但又不想浪费太多空间(Zip64 扩展会占用额外的空间)。不幸的是,一些 ZIP 实现不理解 Zip64 扩展字段,或者无法解析在本地文件头中存在但在中央目录中不存在扩展字段的存档,Java 5 的 java.util.zip 包就是这样一个实现,这就是为什么 jar 任务默认设置为 never。使用 as-needed 创建的存档可以使用 Java 6 及更高版本无问题地读取。

作为嵌套元素指定的参数

任何资源集合

使用资源集合来选择要存档的文件组。

在 Ant 1.7 之前,只支持 <fileset><zipfileset> 作为嵌套元素。

zipgroupfileset

<zipgroupfileset> 允许将多个 zip 文件合并到存档中。在此文件集中找到的每个文件都以与 zipfileset src 文件相同的方式添加到存档中。

<zipgroupfileset> 是一个文件集,并支持其所有属性和嵌套元素。

示例

htdocs/manual 目录中的所有文件压缩到 ${dist} 目录中的名为 manual.zip 的文件中。

<zip destfile="${dist}/manual.zip"
     basedir="htdocs/manual"/>

htdocs/manual 目录中的所有文件压缩到 ${dist} 目录中的名为 manual.zip 的文件中。如果 manual.zip 不存在,则创建它;否则,使用新文件/更改的文件更新它。

<zip destfile="${dist}/manual.zip"
     basedir="htdocs/manual"
     update="true"/>

压缩 htdocs/manual 目录中的所有文件。排除 mydocs 目录中的文件或名为 todo.html 的文件。

<zip destfile="${dist}/manual.zip"
     basedir="htdocs/manual"
     excludes="mydocs/**, **/todo.html"/>

压缩 htdocs/manual 目录中的所有文件。只压缩 api 目录下的 html 文件,并排除名为 todo.html 的文件。

<zip destfile="${dist}/manual.zip"
     basedir="htdocs/manual"
     includes="api/**/*.html"
     excludes="**/todo.html"/>

压缩 htdocs/manual 目录中的所有文件,并添加当前目录中的 ChangeLog.txt 文件。 ChangeLog.txt 将被添加到 ZIP 文件的顶部,就像它位于 htdocs/manual/ChangeLog.txt 中一样。

<zip destfile="${dist}/manual.zip">
  <fileset dir="htdocs/manual"/>
  <fileset dir="." includes="ChangeLog.txt"/>
</zip>

htdocs/manual 目录中的所有文件压缩到存档中的 docs/user-guide 目录中,将当前目录中的 ChangeLog27.txt 文件添加为 docs/ChangeLog.txt,并将 examples.zip 中的所有 html 文件包含在 docs/examples 下。

<zip destfile="${dist}/manual.zip">
  <zipfileset dir="htdocs/manual" prefix="docs/user-guide"/>
  <zipfileset dir="." includes="ChangeLog27.txt" fullpath="docs/ChangeLog.txt"/>
  <zipfileset src="examples.zip" includes="**/*.html" prefix="docs/examples"/>
</zip>

存档最终可能包含以下文件

    docs/user-guide/html/index.html
    docs/ChangeLog.txt
    docs/examples/index.html

htdocs/manual 目录中的所有文件压缩到存档中的 docs/user-guide 目录中,并将与 examples*.zip 匹配的任何文件中的所有文件包含在内,例如 examples1.zipexamples_for_brian.zip 中的所有文件。

<zip destfile="${dist}/manual.zip">
  <zipfileset dir="htdocs/manual" prefix="docs/user-guide"/>
  <zipgroupfileset dir="." includes="examples*.zip"/>
</zip>

可以使用以下方法实现相同的效果

<zip destfile="${dist}/manual.zip">
  <mappedresources>
    <fileset dir="htdocs/manual"/>
    <globmapper from="*" to="docs/user-guide/*"/>
  </mappedresources>
  <archives>
    <zips>
      <fileset dir="." includes="examples*.zip"/>
    </zips>
  </archives>
</zip>

将 TAR 存档重新打包为 ZIP 存档。如果 Unix 文件权限已作为 TAR 文件的一部分存储,它们将保留在生成的 ZIP 存档中。

<zip destfile="release.zip">
  <tarfileset src="release.tar"/>
</zip>