使不能运行的JAR文件可以利用java -jar运行
副标题#e#
摘要
本文展示如何将不行运行的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) {
System.out.println("Usage: MakeJarRunnable "
+ "<jar file> <Main-Class> <output>");
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();
}
#p#副标题#e#
配置Main-Class属性
我们将Main-Class条目放到manifest文件的主要属性部门。一旦我们从manifest工具得到了这个属性集我们就可以配置适当的主类。然而假如一个Main-Class属性已经存在于本来的JAR时怎么办?这个措施简朴的打印一个告诫并退出。或者我们可以增加一个呼吁行参数汇报措施用新的值替换已经存在的谁人值.
Attributes a = manifest.getMainAttributes();
String oldMainClass = a.putValue("Main-Class", args[1]);
//If an old value exists, tell the user and exit
if (oldMainClass != null) {
System.out.println("Warning: old Main-Class value is: "
+ oldMainClass);
System.exit(1);
}
输出新的JAR
我们需要建设一个新的jar文件,因为我们必需利用JarOutputStream类。留意我们必需担保没有将输入作为输出利用。作为替代,也许措施应该思量两个jar文件沟通而且提示用户是否包围本来的。然而我将这个保存给读者作为操练。
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声明。
利用典型
#p#分页标题#e#
让我们用一个典型来利用这个措施。假设你有一个应用其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。
本文配套源码