分享
 
 
 

使不能运行的JAR文件可以使用java -jar运行

王朝厨房·作者佚名  2007-01-04
窄屏简体版  字體: |||超大  

使不能运行的JAR文件可以使用java -jar运行

摘要

本文展示如何将不可运行的JAR变为可运行的,并且不用直接操作manifest文件。你将学会开发一个短小的程序使得任何JAR文件都可以使用java -jar命令或者通过在像Windows上双击而运行。

你可以将一个应用的所有类和资源打包到一个JAR文件中。实际上,那就是jar文件的一个目的。另外一个目的是让用户可以非常容易的执行存储在JAR文件中的应用,那么为什么当他们可以成为一等公民而和本机可执行程序等同的时候,我们为什么要让他们只承担包的功能而成为java世界中的二等公民呢?

要执行一个jar文件,你可以使用java命令的-jar选项。例如你有一个可运行的文件名为myjar.jar的JAR文件,因为它是可运行的,你可以像这样执行它:java -jar myjar.jar

另外,当JRE安装在像Windows这样的操作系统上时,将jar文件和JVM关联后你就可以双击他们运行应用了。这些JAR必须是可运行的。

问题是:你如何让一个JAR是可运行的?

manifest文件和Main-Class条目

在大部分JAR文件中,META-INF目录下会有一个MANIFEST.MF文件,在那个文件中有一个特殊的条目Main-Class,它告诉java -jar命令去执行那么类。

问题是你必须自己恰当的将这个特殊条目加到manifest文件中:它必须位于特定的位置并且必须符合特定的格式,然而有些人不喜欢编辑配置文件。

让API帮你做

从Java 1.2开始引人的java.util.jar包可以让你操作jar文件(注意:它建立在java.util.zip包的基础上)。更确切的说法是,java.util.jar可以让你通过Manifest类非常容易的操作那个特殊的manifest文件。

让我们编写一个程序使用那个API。首先这个程序必须知道三件事情:

1. 我们希望可以执行的JAR

2. 我们希望执行的主类(这个类必须存在于JAR内)

3. 新的JAR文件的文件名,因为我们不应该简单的覆盖那些文件

编写程序

上面的列表将会构成我们的程序的参数,基于这一点,让我们为这个应用挑选一个合适的名字。MakeJarRunnable听起来如何?

检查main的参数

假设我们的main入口是一个标准的main(String[])方法,我们首先应该检查程序的参数:

if (args.length != 3) {

java/lang/System.java.html" target="_blank">System.out.println("Usage: MakeJarRunnable "

+ "<jar file> <Main-Class> <output>");

java/lang/System.java.html" target="_blank">System.exit(0);

}

请注意参数列表是如何被解释的,因为这对于后面的代码是非常重要的。参数的顺序和内容并不是硬性设置的,但是如果你改变它们也要记得适当的修改其他的代码。

访问JAR和它的manifest文件

首先我们必须创建一些知道JAR和manifest文件的对象:

//Create the JarInputStream object, and get its manifest

JarInputStream jarIn = new JarInputStream(new FileInputStream(args[0]));

Manifest manifest = jarIn.getManifest();

if (manifest == null) {

//This will happen if no manifest exists

manifest = new Manifest();

}

设置Main-Class属性

我们将Main-Class条目放到manifest文件的主要属性部分。一旦我们从manifest对象获得了这个属性集我们就可以设置适当的主类。然而如果一个Main-Class属性已经存在于原来的JAR时怎么办?这个程序简单的打印一个警告并退出。或许我们可以增加一个命令行参数告诉程序用新的值替换已经存在的那个值.

Attributes a = manifest.getMainAttributes();

java/lang/String.java.html" target="_blank">String oldMainClass = a.putValue("Main-Class", args[1]);

//If an old value exists, tell the user and exit

if (oldMainClass != null) {

java/lang/System.java.html" target="_blank">System.out.println("Warning: old Main-Class value is: "

+ oldMainClass);

java/lang/System.java.html" target="_blank">System.exit(1);

}

输出新的JAR

我们需要创建一个新的jar文件,因为我们必须使用JarOutputStream类。注意我们必须保证没有将输入作为输出使用。作为替代,也许程序应该考虑两个jar文件相同并且提示用户是否覆盖原来的。然而我将这个保留给读者作为练习。

java/lang/System.java.html" target="_blank">System.out.println("Writing to " + args[2] + "...");

JarOutputStream jarOut = new JarOutputStream(new FileOutputStream(args[2]),

manifest);

我们必须将原来的JAR中的每个条目都写到新的JAR中,因为对那些条目迭代:

//Create a read buffer to transfer data from the input

byte[] buf = new byte[4096];

//Iterate the entries

JarEntry entry;

while ((entry = jarIn.getNextJarEntry()) != null) {

//Exclude the manifest file from the old JAR

if ("META-INF/MANIFEST.MF".equals(entry.getName())) continue;

//Write the entry to the output JAR

jarOut.putNextEntry(entry);

int read;

while ((read = jarIn.read(buf)) != -1) {

jarOut.write(buf, 0, read);

}

jarOut.closeEntry();

}

//Flush and close all the streams

jarOut.flush();

jarOut.close();

jarIn.close();

完整程序

当然我们必须将这些代码放到一个类里面的main方法里面,并且具有合适的import声明。

使用范例

让我们用一个范例来使用这个程序。假设你有一个应用其main入口点是类HelloRunnableWorld(这个是它的全类名,也就是包含包名),同样假设你已经创建了一个名字为myjar.jar的JAR,包含整个应用。对于这个jar,我们像这样运行MakeJarRunnable:

java MakeJarRunnable myjar.jar HelloRunnableWorld myjar_r.jar

再强调一次,就像早先提到的,注意参数列表的顺序。如果忘记了顺序,以无参的形式运行程序它就会告诉你使用信息。

使用java -jar命令运行myjar.jar和myjar_r.jar,注意它们的差异。完成这些之后,查看一下它们的manifest文件(META-INF/MANIFEST.MF)。

这里有一个建议:将MakeJarRunnable制作成一个可以运行的JAR!

运行它

通过双击一个JAR或者使用简单的命令总是比将它包含在你的classpath并运行特定的main类方便。为了帮助你作到这一点,JAR规范为JAR的manifest文件提供了一个Main-Class属性。我在这里提出的这个程序让你利用Java的JAR API非常容易的操作这个属性并制作你自己的可运行的JAR。

完整源代码

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有