6.12.1 jar命令详解

6.12.1 jar命令详解

jar是随JDK自动安装的,在JDK安装目录下的bin目录中,Windows下文件名为jar.exe, Linux下文件名为jar

查看jar帮助文档

在CMD中输入jar,可以看到jar命令的帮助文档.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
C:\Users\lan>jar
用法: jar {ctxui}[vfmn0PMe] [jar-file] [manifest-file] [entry-point] [-C dir] files ...
选项:
-c 创建新档案
-t 列出档案目录
-x 从档案中提取指定的 (或所有) 文件
-u 更新现有档案
-i 为指定的 jar 文件生成索引信息

-v 在标准输出中生成详细输出
-f 指定档案文件名
-m 包含指定清单文件中的清单信息
-n 创建新档案后执行 Pack200 规范化
-0 仅存储; 不使用任何 ZIP 压缩
-P 保留文件名中的前导 '/' (绝对路径) 和 ".." (父目录) 组件
-M 不创建条目的清单文件
-e 为捆绑到可执行 jar 文件的独立应用程序
指定应用程序入口点

-C 更改为指定的目录并包含以下文件
如果任何文件为目录, 则对其进行递归处理。
清单文件名, 档案文件名和入口点名称的指定顺序与 'm', 'f' 和 'e' 标记的指定顺序相同。

示例 1: 将两个类文件归档到一个名为 classes.jar 的档案中:
jar cvf classes.jar Foo.class Bar.class
示例 2: 使用现有的清单文件 'mymanifest' 并
foo/ 目录中的所有文件归档到 'classes.jar' 中:
jar cvfm classes.jar mymanifest -C foo/ .

1. 创建JAR文件

命令:jar cf test.jar -C dist/ .

1
2
3
4
-c  创建新档案
-f 指定档案文件名

-C 更改为指定的目录并包含以下文件

将当前路径下的dist路径下的全部内容生成一个test.jar文件。如果当前目录中已经存在test.jar文件,那么该test.jar文件将被覆盖。

2. 创建JAR文件 并显示压缩过程

命令:jar cvf test.jar -C dist/ .

1
2
3
4
5
-c  创建新档案
-v 在标准输出中生成详细输出
-f 指定档案文件名

-C 更改为指定的目录并包含以下文件
1
2
3
4
5
G:\Desktop\随书源码\疯狂Java讲义(第4版)光盘\codes\06\6.12>jar cvf test.jar -C dist/ .
已添加清单
正在添加: test/(输入 = 0) (输出 = 0)(存储了 0%)
正在添加: test/Test.class(输入 = 419) (输出 = 291)(压缩了 30%)
正在添加: test/Test.java(输入 = 421) (输出 = 320)(压缩了 23%)

3. 不使用清单文件

命令:jar cvfM test.jar -C dist/ .

1
2
3
4
5
6
-c  创建新档案
-v 在标准输出中生成详细输出
-f 指定档案文件名
-M 不创建条目的清单文件

-C 更改为指定的目录并包含以下文件
1
2
3
4
G:\Desktop\随书源码\疯狂Java讲义(第4版)光盘\codes\06\6.12>jar cvfM test.jar  -C dist/ .
正在添加: test/(输入 = 0) (输出 = 0)(存储了 0%)
正在添加: test/Test.class(输入 = 419) (输出 = 291)(压缩了 30%)
正在添加: test/Test.java(输入 = 130) (输出 = 118)(压缩了 9%)

该命令的结果与第2个命令类似,其中M选项表明不生成清单文件。因此生成的test.jar中没有包含清单文件(META-INF/MANIFEST.MF),打包过程的信息也略有差别。

4. 自定义清单文件内容

命令格式:jar cvfm JAR保存路径 清单文件路径 -C 目录 文件
运行结果与第2个命令相似,显示信息也相同,其中小写的m选项用于指定读取用户清单文件信息。因此在生成的JAR包中清单文件META-INF/MANIFEST.MF的内容有所不同,它会在原有清单文件基础上增加MANIFEST.MF文件的内容。

当开发者向MANIFEST.MF清单文件中增加自己的内容时,就需要借助于自己的清单文件了,清单文件只是一个普通的文本文件,使用记事本编辑即可。清单文件的内容由如下格式的多个key-value对组成。格式如下:
key:空格value

清单文件的内容格式

  1. 每行只能定义一个key-value对,每行的key-value对之前不能有空格,即key-value对必须顶格写。
  2. 每组key-value对之间以英文冒号后紧跟一个英文空格分隔,少写了冒号或者空格都是错误的.
  3. 文件开头不能有空行。
  4. 文件必须以一个空行结束。

可以将上面文件保存在任意位置,以任意文件名存放。例如将上面文件保存在当前路径下,文件名为a.txt。使用如下命令即可将清单文件中的key-value对提取到META- INF/MANIFEST.MF文件中。
jar cvfm test.jar a.txt -C dist/ .

实例

目录结构

1
2
3
4
5
6
7
8
9
10
11
G:\Desktop\随书源码\疯狂Java讲义(第4版)光盘\codes\06\6.12
├─a.txt
├─dist\
│ └─test\
│ ├─Test.class
│ └─Test.java
├─dist7\
│ └─test\
│ ├─Test.class
│ └─Test.java
└─test.jar

a.txt文件内容:

1
2
G:\Desktop\随书源码\疯狂Java讲义(第4版)光盘\codes\06\6.12>type a.txt
Hello: HelloWorld

a.txt中的内容添加到清单文件中:

1
2
3
4
5
6
7
G:\Desktop\随书源码\疯狂Java讲义(第4版)光盘\codes\06\6.12>jar cvfm test.jar a.txt -C dist/ .
已添加清单
正在添加: test/(输入 = 0) (输出 = 0)(存储了 0%)
正在添加: test/Test.class(输入 = 419) (输出 = 291)(压缩了 30%)
正在添加: test/Test.java(输入 = 130) (输出 = 118)(压缩了 9%)

G:\Desktop\随书源码\疯狂Java讲义(第4版)光盘\codes\06\6.12>

生成的清单文件内容:

1
2
3
Manifest-Version: 1.0
Hello: HelloWorld
Created-By: 1.8.0_131 (Oracle Corporation)

5. 查看JAR包内容

命令:jar tf test.jar

1
2
-t  列出档案目录
-f 指定档案文件名
1
2
3
4
5
6
G:\Desktop\随书源码\疯狂Java讲义(第4版)光盘\codes\06\6.12>jar tf test.jar
META-INF/
META-INF/MANIFEST.MF
test/
test/Test.class
test/Test.java

JAR包中的文件路径和文件非常多时,因为命令行窗口能显示的行数有限,所以直接执行该命令,可能无法看到包的全部内容,此时可利用重定向将显示结果保存到文件中。例如,采用如下命令:jar tf test.jar > test.txt

1
2
3
4
5
6
7
8
G:\Desktop\随书源码\疯狂Java讲义(第4版)光盘\codes\06\6.12>jar tf test.jar > test.txt

G:\Desktop\随书源码\疯狂Java讲义(第4版)光盘\codes\06\6.12>type test.txt
META-INF/
META-INF/MANIFEST.MF
test/
test/Test.class
test/Test.java

6. 查看JAR包详细内容

命令:jar tvf test.jar

1
2
3
4
5
6
G:\Desktop\随书源码\疯狂Java讲义(第4版)光盘\codes\06\6.12>jar tvf test.jar
0 Sun Sep 29 16:36:50 CST 2019 META-INF/
88 Sun Sep 29 16:36:50 CST 2019 META-INF/MANIFEST.MF
0 Sat Sep 28 23:11:18 CST 2019 test/
419 Sat Sep 28 23:11:18 CST 2019 test/Test.class
130 Sat Sep 28 23:10:28 CST 2019 test/Test.java

7. 解压缩

命令:jar xf test.jar,这个命令会解压到当前目录下。

1
2
-x  从档案中提取指定的 (或所有) 文件
-f 指定档案文件名

示例

jar xf JAR包默认解压在当前路径下,为了观察明显,先把test.jar复制到其他地方.

1
2
G:\Desktop\随书源码\疯狂Java讲义(第4版)光盘\codes\06\6.12>copy test.jar Copy
已复制 1 个文件。

然后再解压

1
2
G:\Desktop\随书源码\疯狂Java讲义(第4版)光盘\codes\06\6.12>cd Copy
G:\Desktop\随书源码\疯狂Java讲义(第4版)光盘\codes\06\6.12\Copy>jar xf test.jar

解压后的效果如下:

1
2
3
4
5
6
7
8
G:\Desktop\随书源码\疯狂Java讲义(第4版)光盘\codes\06\6.12\Copy>mytree f
G:\Desktop\随书源码\疯狂Java讲义(第4版)光盘\codes\06\6.12\Copy
├─META-INF\
│ └─MANIFEST.MF
├─test\
│ ├─Test.class
│ └─Test.java
└─test.jar

8. 带提示信息解压缩

命令:jar xvf test.jar
这个命令的解压缩效果与第7个命令相同,但系统会显示解压过程的详细信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
G:\Desktop\随书源码\疯狂Java讲义(第4版)光盘\codes\06\6.12\Copy>jar xvf test.jar
已创建: META-INF/
已解压: META-INF/MANIFEST.MF
已创建: test/
已解压: test/Test.class
已解压: test/Test.java

G:\Desktop\随书源码\疯狂Java讲义(第4版)光盘\codes\06\6.12\Copy>mytree f
G:\Desktop\随书源码\疯狂Java讲义(第4版)光盘\codes\06\6.12\Copy
├─META-INF\
│ └─MANIFEST.MF
├─test\
│ ├─Test.class
│ └─Test.java
└─test.jar

9. 更新JAR文件

命令:jar uf test.jar Hello.class,这个命令会更新test.jar中的Hello.class文件。如果test.jar中已有Hello.class件,则使用新的Hello.class文件替换原来的Hello.class文件;如果test.jar中没有Helo.class文件,则把新的Hello.class文件添加到test.jar文件中。

10.更新时显示详细信息

命令:jar uvf test.jar Hello.class

1.11 创建多版本JAR包

多版本JAR包是JDK9新增的功能,它允许在同一个JAR包中包含针对多个Java版本的cass文件。JDK9jar命令增加了一个 --release选项,用于创建多版本JAR包,注意,只有Java9之后才支持多版本JAR包。

如何使用指定版本的Java进行编译

在使用多版本JAR包之前,可以使用Javac--release选项针对指定Java版本进行编译。比如命令:
javac --release 7 Test java
上面命令代表使用Java7的语法来编译Test java。如果你的Test java中使用了Java8Java9的语法,程序将会编译失败。

如果创建多版本JAR包

假如将针对Java7编译的所有class文件放在dist7目录下,针对Java9编译的所有class文件放在dist目录下。接下来可用如下命令来创建多版本JAR包:
jar cvf test.jar -C dist7/ . --release 9 -C dist/ .

特定版本在JAR包中的位置

这样就创建了一个多版本JAR包,在该多版本JAR包内,特定版本的文件位于META-INF/versions/N目录下,其中N代表版本号。