将java项目导出成jar-exe-安装程序

关于将java项目导出成exe文件

第一步:通过eclipse将java项目导出成可执行的jar包

选择项目->Export>Runnable JAR file

 

导出之后是一个可执行的jar包,可以直接执行。接下来把jre整个文件夹复制到与jar包同目录中,同时把把项目中引用的第三方包(ceflib)拷贝到jrebin目录中去。

 

第二步:精简jre

运行cmd,进入dos界面,设置java临时路径

set path=D:\HCIM2\jre6\bin;

通过jar命令运行导出来的jar包

java -jar  im.jar

第一次运行时会报错提醒

这是因为导出可执行jar包是并没有导出位于项目根目录的图片和部分配置文件,我们只需要把这些文件复制到im.jar同目录中即可

 

接下来就是精简jre

开始时根据网上办法(http://yaojialing.iteye.com/blog/1067409)通过将项目操作到底,精简rt和charesets两个大jar文件,精简之后小了很多  具体操作如下:

通过谷歌搜索得到的精简思路:

把自己的应用程序打包成jar,然后通过jar命令运行这个jar,把jar所需的类全部打印到一个文本文件里面,把文本文件里面的类提取出来,重新打包。覆盖JRE目录中的JAR包。去掉JRE下bin目录和lib目录中不需要得。瘦身完成。

 

应用程序打包后是test.jar,jre(目录) 也和它同一文件夹,写一个CMD脚本方便测试:

Js代码  

1.  @echo off  

2.  set path=./jre6/bin  

3.  java -jar -verbose:class test.jar >>class.txt  

4.  pause  

 

这样程序使用的就是当前目录下的jre,程序运行后,最好把所有的功能使用一遍,这样输出了一个文件class.txt,里面有所有需要的class,其格式如下:

Js代码  

1.  [Opened D:\data\dict\jre\lib\rt.jar]  

2.  [Loaded java.lang.Object from D:\data\dict\jre\lib\rt.jar]  

3.  [Loaded java.io.Serializable from D:\data\dict\jre\lib\rt.jar]  

4.  [Loaded java.lang.Comparable from D:\data\dict\jre\lib\rt.jar]  

5.  [Loaded java.lang.CharSequence from D:\data\dict\jre\lib\rt.jar]  

6.  [Loaded org.apache.lucene.index.CompoundFileReader$FileEntry from file:/D:/data/dict/dict.jar]  

输出的class文件里面可能还包含其他应用的jar包,如:charsets.jar。这样就需要把class文件里面的信息按rt和charsets分成两类分别放到两个txt文件里面:rt_class.txt,charsets.txt

我们依照这个文件来裁剪rt.jar:
首先在utralEdit中进行一些处理,去掉所有不是rt.jar中的class的行,去掉from后面的,去掉loaded等无关项目,再把“.”替换成“/”.这个可以利用正则表达式等轻松处理。处理完后得到的文件类似如下格式:

 rt_class.txt

Java代码  

1.  java/lang/Object  

2.  java/io/Serializable  

3.  java/lang/Comparable  

4.  java/lang/CharSequence  

5.  java/lang/String   

 

我们依照这个文件来裁剪charsets.jar:
首先在utralEdit中进行一些处理,去掉所有不是charsets.jar中的class的行,去掉from后面的,去掉loaded等无关项目,再把“.”替换成“/”.这个可以利用正则表达式等轻松处理。处理完后得到的文件类似如下格式:

charsets.txt

Java代码  

1.  sun/nio/cs/ext/ExtendedCharsets   

2.  sun/nio/cs/ext/GBK   

3.  sun/nio/cs/ext/DoubleByteDecoder   

4.  sun/nio/cs/ext/GBK$Decoder   

5.  sun/nio/cs/ext/DoubleByteEncoder   

6.  sun/nio/cs/ext/GBK$Encoder   

 然后写一个脚本或者程序处理,从rt或charsets中把需要的的class拷贝到另一个对应的文件夹rt1或charsets1,这里参考网上的一个JAVA抽取程序。

 

在运行下面JAVA程序之前需要将JRE目录中rt.jar,charsets.jar分别解压到相应目录

 

代码如下:

Java代码  

1.  package com.ccic.greenjvm;  

2.    

3.  import java.io.File;  

4.  import java.io.FileInputStream;  

5.  import java.io.FileOutputStream;  

6.  import java.io.IOException;  

7.  import java.io.InputStreamReader;  

8.  import java.io.LineNumberReader;  

9.    

10. public class ReduceRt {  

11.     // 文件拷贝  

12.     public static boolean copy(String file1, String file2) {  

13.         try // must try and catch,otherwide will compile error  

14.         {  

15.             // instance the File as file_in and file_out  

16.             java.io.File file_in = new java.io.File(file1);  

17.             java.io.File file_out = new java.io.File(file2);  

18.             FileInputStream in1 = new FileInputStream(file_in);  

19.             FileOutputStream out1 = new FileOutputStream(file_out);  

20.             byte[] bytes = new byte[1024];  

21.             int c;  

22.             while ((c = in1.read(bytes)) != -1)  

23.                 out1.write(bytes, 0, c);  

24.             in1.close();  

25.             out1.close();  

26.             return (true); // if success then return true  

27.         } catch (Exception e) {  

28.             System.out.println("Error!");  

29.             return (false); // if fail then return false  

30.         }  

31.     }  

32.   

33.     // 读取路径,copy  

34.     public static int dealClass(String needfile, String sdir, String odir) throws IOException {  

35.         int sn = 0// 成功个数  

36.   

37.         File usedclass = new File(needfile);  

38.         if (usedclass.canRead()) {  

39.             String line = null;  

40.             LineNumberReader reader = new LineNumberReader(new InputStreamReader(new FileInputStream(usedclass),  

41.                     "UTF-8"));  

42.             while ((line = reader.readLine()) != null) {  

43.                 line = line.trim();  

44.                 int dirpos = line.lastIndexOf("/");  

45.                 if (dirpos > 0) {  

46.                     String dir = odir + line.substring(0, dirpos);  

47.                     File fdir = new File(dir);  

48.                     if (!fdir.exists())  

49.                         fdir.mkdirs();  

50.                     String sf = sdir + line + ".class";  

51.                     String of = odir + line + ".class";  

52.                     boolean copy_ok = copy(sf.trim(), of.trim());  

53.                     if (copy_ok)  

54.                         sn++;  

55.                     else {  

56.                         System.out.println(line);  

57.                     }  

58.   

59.                 }  

60.   

61.             }  

62.         }  

63.         return sn;  

64.   

65.     }  

66.   

67.     public static void main(String[] args) {  

68.         String needfile = "D:/greanjvm/rt_class.txt";//运行JAR生成的,应用程序所需类的txt文件 

69.         String sdir = "D:/greanjvm/rt/"//rt.jar解压后的目录  

70.         String odir = "D:/greanjvm/rt1/";//抽取的类存放目录  

71.         try {  

72.             int sn = dealClass(needfile, sdir, odir);  

73.             System.out.print(sn);  

74.         } catch (IOException e) {  

75.             e.printStackTrace();  

76.         }  

77.   

78.     }  

79. }  

 

所需的类都抽取到rt1目录之后,把原rt目录中的“META-INF”文件夹拷贝到rt1下面,进入rt1目录,用rar压缩工具打包成rt.zip,改名为rt.jar,然后替换jre6/lib目录下的rt.jar。

 

charsets1目录处理同上。

 

所需类的精简工作已经完成,接下来精简其他的。

 

1、Jre目录下的license都删除,只留bin和lib目录

2、bin下的执行文件需要运行jar时用DLL_Killer工具查看使用到了哪些文件

3、lib下只要保留 rt,charsets库就可以了(因为应用程序只用到了这两个)。

4、除了i386和zi两个子目录外,其余的子目录都可以不要(原则上都要自己试试看删除其他目录会不会报错)。

5、Zi下只需要保留自己地区的子目录和其下的一些文件就可以(这里Zi下我只保留了America文件夹)。

6、Lib下除了库之外的属性文件都要保留。

 

优化完成!!!!!!!!!!!

 

注意事项:

1、精简BIN目录
  *
运行JAR包时需指定PATH路径,不然会默认搜索环境变量中的JDK路径。
  *
DLL_Killer工具查看任务管理器中java.exe调用的DLL

2、精简LIB目录
  *
抽取出的类重新打包成rt.jar时要注意,用JAR命令和rar工具打的jar包都不行。解决如下:
 -
将原生的rt.jarrar打开,然后进入相关目录,删除掉相关目录或者文件,再把抽取出来的类拖进来就行了。
  *zi
文件夹下只留America文件夹

个人的办法

按照上面的办法能得到一个非常精简的jre包,而事实上这个jre包却不能用,一直在提醒缺少类文件引用以及JavaThread "AWT-EventQueue-0"等错误。后来采用了一种比较笨的方法,自己逐步的删除bin目录的文件以及jre的文件,看项目是否能够正常运行,能则可以删除,反之保留。精简charsets.jar可以完全参考上述办法,而在精简rt.jar文件时可以参考着上述精简后的文件,逐步删除,尝试是否项目正常运行。

 

第三步:将jar打包exe文件

使用工具exe4j,在使用之前一定把exe4j注册掉,否则倒出来的exe不能执行。

参考网上方法(http://www.blogjava.net/pengo/archive/2010/03/12/315278.html)

 

第1步,默认即可,直接点击next。

 

第2步,选择"JAR inEXE",点击next

 

第3步,上面是项目名称,可随便填写,下面一个是把jar转成exe文件后,exe文件的输出目录(建议和原jar路径一致):第4步,HtmlFrame.jar是GUI程序,所以选第一个,Executable name是生成的exe文件的名字,Icon File可以选择是这个exe文件的图标

 

第5步,单击绿色的"+"号,在弹出的窗口中点Archive,然后找到HtmlFrame.jar,"OK"后返回,在下面的ClassPath里就出现jar文件路径后,再在上面Main Class栏内点击找到main()方法所在的类,这一步即算完成:第6步,确认系统的JRE版本,上面填个1.4,下面填1.6:

 

上边配置的程序只能在安装有JRE的机器上执行,但发布时要考虑用户的机器上是否安装有JRE,总不能发布一个程序还要用户自己安装个JRE,下面为将要生成的exe指定jre路径,在这里单击advanced options,选择searchsequence。先把Search Sequence列表内所有选项删除,再点击绿色"+",Entry Type选择Directory,再在下边的路径选择中选择HtmlFrame2\jre6,

 

单击ok后,再从图中单击advanced options,并选择preferred VM,在弹出的窗口中选择clienthostspot VM,单击next按钮继续:

 

第7步,设置程序的启动画面,单击next

 

第8步,设置提示消息的语言,单击next

 

第9步编译

第10步,完成

 

第四步:将整个文件夹渲染成安装程序,使用工具inno setup5

打开inno setup进行渲染。。。

当到达步骤Application Files时进行选择exe、及其他配置文件(包含jar文件等)

但选择jre6时先将jre6整个文件夹复制到一新目录中命名为jre,在选择jre时直接定位到jre文件夹,如果直接选择jre6的话,那么exe文件江河jre6中的bin文件夹和lib文件夹同目录。

 

以下为渲染时的脚本

 

; Script generated by the Inno Setup Script Wizard.

; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPTFILES!

 

#define MyAppName "IM"

#define MyAppVersion "1.0"

#define MyAppPublisher "HnTest"

#define MyAppExeName "MyProg.exe"

 

[Setup]

; NOTE: The value of AppId uniquely identifies this application.

; Do not use the same AppId value in installers for other applications.

; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)

AppId={{D132D0C4-1860-46E9-95CB-7EB98EC0F909}

AppName={#MyAppName}

AppVersion={#MyAppVersion}

;AppVerName={#MyAppName} {#MyAppVersion}

AppPublisher={#MyAppPublisher}

DefaultDirName={pf}\{#MyAppName}

DefaultGroupName={#MyAppName}

OutputBaseFilename=IM

Compression=lzma

SolidCompression=yes

 

[Languages]

Name: "english"; MessagesFile:"compiler:Default.isl"

 

[Tasks]

Name: "desktopicon"; Description:"{cm:CreateDesktopIcon}"; GroupDescription:"{cm:AdditionalIcons}"; Flags: unchecked

 

[Files]

Source: "D:\Program Files (x86)\Inno Setup5\Examples\MyProg.exe"; DestDir: "{app}"; Flags: ignoreversion

Source: "D:\IM_NEW\arrow_left.png"; DestDir:"{app}"; Flags: ignoreversion

Source: "D:\IM_NEW\arrow_refresh.png"; DestDir:"{app}"; Flags: ignoreversion

Source: "D:\IM_NEW\arrow_right.png"; DestDir:"{app}"; Flags: ignoreversion

Source: "D:\IM_NEW\client.properties"; DestDir:"{app}"; Flags: ignoreversion

Source: "D:\IM_NEW\Im.exe4j"; DestDir: "{app}";Flags: ignoreversion

Source: "D:\IM_NEW\im.jar"; DestDir: "{app}";Flags: ignoreversion

Source: "D:\IM_NEW\page-loader.gif"; DestDir:"{app}"; Flags: ignoreversion

Source: "D:\IM_NEW\webAddress.properties"; DestDir:"{app}"; Flags: ignoreversion

Source: "D:\IM_NEW\jre\*"; DestDir: "{app}"; Flags:ignoreversion recursesubdirs createallsubdirs

; NOTE: Don't use "Flags: ignoreversion" on any shared systemfiles

 

[Icons]

Name: "{group}\{#MyAppName}"; Filename:"{app}\{#MyAppExeName}"

Name: "{commondesktop}\{#MyAppName}"; Filename:"{app}\{#MyAppExeName}"; Tasks: desktopicon

 

[Run]

Filename: "{app}\{#MyAppExeName}"; Description:"{cm:LaunchProgram,{#StringChange(MyAppName, '&','&&')}}"; Flags: nowait postinstall skipifsilent

 

 

 

渲染成功,进行测试

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值