Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 486|回复: 0

[Java基础知识]用java API制作可执行JAR文件

[复制链接]
  • TA的每日心情
    开心
    2021-3-12 23:18
  • 签到天数: 2 天

    [LV.1]初来乍到

    发表于 2014-10-1 23:09:31 | 显示全部楼层 |阅读模式
    作者:Shawn Silverman 翻译:Sean
           本文阐述了如何把一个不可执行的java ArcHive(JAR)文件变成可执行,而不用直接操作manifest文件。你会学到写出短小的一个程序,通过运行
    java -jar
    命令或在像windows一样的操作系统里面用双击鼠标运行任何JAR文件。        你可以很容易地把应用程序的一整套class文件和资源文件打包到一个JAR中。事实上这就是jar文件存在的一个目的。另外一个目的就是让用户能很容易地执行被打包到jar文件里面的应用程序。那么为什么jar文件仅仅作为文件在整个java里面占据了次要的地位,而本地执行则被忽视?        要执行一个jar文件,你可以使用java命令的-jar选项。举一个例子来说,假如你有个名叫myjar.jar的文件。这个jar是可以运行的,你可以运行它:
    java -jar myjar.jar

           另外一个办法就是,当Java Runtime Environment(JRE)已经被安装到一个像windows的操作系统上,将jar文件与JVM关联(关联java.exe跟jar文件)在一起你就可以通过双击jar来运行这个应用程序。当然,jar文件必须是可执行的。  
      
    现在的问题是:如何做一个可以执行的jar? manifest文件以及Main-class入口
          在大多数jar中,都在一个叫META-INF的目录里面保存了一个叫MANIFEST.MF的文件。那个文件里面,
    包含了一个特殊表项名字叫Main-Class,告诉java -jar命令应该执行哪个class. 问题是你必须为manifest文件手工加入适当表项,而且必须在一定的位置和用一定的格式。不幸的是,不是每个人都喜欢打开写字板编辑配置文件。 让API帮你完成任务
            自从java1.2发布以来,一个叫java.uil.jar包的出现,让你能够方便处理jar文件。
    (注意:该包基于java.util.zip)特别地,jar包让你通过Mainfest类,可以容易操作
    那些manifest文件. 就让我们用这个API写一个程序吧。首先,这个程序必须知道三样东西:
    1。我们要使之可运行的jar文件。
    2。运行jar的主类(这个类必须包含在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和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文件的main属性部分。一旦从manifest对象获得这个属性,就可以设置需要的main class。然而,如果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代码。完整程序:
    1. import java.io.FileInputStream;
    2. import java.io.FileOutputStream;
    3. import java.io.IOException;
    4. import java.util.jar.*;
    5. /**
    6. * This utility makes a JAR runnable by inserting a [code]Main-Class
    复制代码

    * attribute into the Manifest.
    *
    * @author Shawn Silverman
    */
    public class MakeJarRunnable {
        public static void main(String[] args) throws IOException {
            if (args.length != 3) {
                System.out.println("Usage: MakeJarRunnable "
                                   + "
      
       
       ");
                System.exit(0);
            }
            // 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 there is no Manifest
                manifest = new Manifest();
            }
            Attributes a = manifest.getMainAttributes();
            String oldMainClass = a.putValue("Main-Class", args[1]);
            // If there was an old value there, tell the user about it and exit
            if (oldMainClass != null) {
                System.out.println("Warning: old Main-Class value is: "
                                   + oldMainClass);
                System.exit(1);
            }
            System.out.println("Writing to " + args[2] + "...");
            JarOutputStream jarOut = new JarOutputStream(new FileOutputStream(args[2]),
                                                         manifest);
            // Create a read buffer to be used for transferring 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 out 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();
        }
    }

      
    [/code]          程序使用例子
         让我们把这个程序应用到一个例子里面来。假设你有一个应用程序,该程序的入口点是一个叫HelloRunnableWorld的 类,再假设你已经创建了一个jar叫myjar.jar,包含了整个程序。运行MakeJarRunnable:

      c:java>java MakeJarRunnable myjar.jar HelloRunnableWorld myjar_r.jar

    运行结果: c:java>Hello, Runnable World!

         正如前面提到的,注意一下我的参数顺序。如果你忘记了顺序,没有参数运行一下程序,它会响应出现一个用法提示信息。     尝试对myjar.jar运行java -jar命令。然后对myjar_r.jar。注意区别不同!好了,你完成了这一切了,  浏览一下每个jar的manifest文件(META-INF/MANIFEST.MF)

      
      
       
       

         
       

         
       
      
      

    源码下载:http://file.javaxxz.com/2014/10/1/230931688.zip
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-5-18 18:05 , Processed in 0.407292 second(s), 48 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

    快速回复 返回顶部 返回列表