热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

javajre打包_Java精简Jrejar打包成exe

#开始最近几天都在忙一个事情,那就是尝试精简jre,我想不明白为什么甲骨文官方不出exe打包工具网络上精简jre的文章很多,但是原创的似乎没几个,绝大多数都是转

#开始

最近几天都在忙一个事情,那就是尝试精简jre,我想不明白为什么甲骨文官方不出exe打包工具...

网络上精简jre的文章很多,但是原创的似乎没几个,绝大多数都是转发同一个博客, 这里借鉴了不少思路以及方法 不知道还算不算原创了

这两天收获也是挺大的,在这里和大家分享一下我的成果.以及原理....

谢谢网络上大神们分享的教程受益良多 : )

虽然这篇博文比较长 但是实际上是因为我太啰嗦了........并不难做 并且建议先看一遍大体流程

#成果

ecf0f45abd583325e76beb3cb67e2e05.png

这个是我前不久写的一个聊天室的客户端, 源码在这里 : https://github.com/LonelySinging/JavaChatRoom-client.git

整个jre以及成品jar包加起来打包成exe之后只有11MB了 不过 说真的 还是觉得很大 因为jar包本身只有13KB 那么也就是说 jre环境是真的很大了 完整的jre是197MB了 QAQ

#开始

那么现在就开始吧

假设现在我们有

1. 需要打包的jar包 (我这里是client.jar)

2. 一台装有Java环境的win10 64位电脑 JDK是1.8版本

3. 能运行java代码的环境 (我这里是eclipse)

4. 火绒剑(我是内置版的)

5. notepad++

#分析jre目录 (我也才刚学习java没多久 对于原理性的东西了解的也不多 所以出错了别打我 QAQ)

ed3d2a9874362ed6638587747a0cb1c7.png

这是jdk1.8里面的jre目录 最主要的就是bin和lib目录

#bin目录

bin目录就是java.exe等几个命令所在地了,应该也是JVM虚拟机的本体所在, 我的里面是这样的

062ed086958ae16f3e7f5cbedeaad2da.png

这里有 java.exe 也即是启动jar的关键所在 以及一大堆的dll文件 精简bin目录的关键就是精简这些dll文件,思路就是满足java.exe的运行就可以了

那么 接下来就是想办法知道java.exe到底依赖那些dll了

#lib目录

我的lib目录是这样的

40ccbd51d3aa8612191673734a4d900c.png

大家打开可以看到是一堆不知用途的文件以及各种jar包 那么这里的jar包里面就是我们在写代码的时候调用的类以及方法.

还有字体文件(font文件夹里) 图标资源(images文件夹里面) 还有一个最大的rt.jar文件 大小居然都是60多MB了 所以 精简lib目录的核心就是精简rt.jar文件

精简的思路依旧是删除不需要的就好了

#精简开始

#精简bin目录

1. 把准备打包的jar包复制到bin

2. 新建一个批处理文件(新建文本文档) 添加内容如下 (意思是 运行jar文件 并且把所有输出信息导出到class.txt文件里)

java -jar -verbose:class client.jar >> class.txt

保存 更改名字为 run.bat (注意 这是改了后缀名的 如果没有后缀名 看下面)

fc4438f31842dad950ee4ded43e2eba7.png

3. 双击运行 run.bat 然后对你的应用进行各种操作 是所有的功能都使用一遍(这里指的是,即使是一个编辑框 你也要尝试输入不同的东西 使用方向键操作光标等等 )这个非常重要!!!!!!!!!!! 为的是把所有使用到的类都输出到class.txt文件 (class.txt文件是用来精简lib目录的 这里不管他)

4. 打开火绒剑 (其他的行为检测软件也可以 作用相同就行)  点击进程 -> 然后选择java.exe 然后就可以找到java.exe加载的所有dll文件

62335e5954931b10691280fa337182d0.png

5. 新建一个在桌面上新建一个文件夹 然后 新建两个文件夹(bin和lib) 如图

c1934b4004100d86405678475f2dc0fd.png

6. 在上面火绒剑里面查看所用到的dll以及他们的路径 找到他们 复制到新建的文件夹里的bin文件夹 得到如下 发现瞬间少了很多 (如果不是jre目录下的dll文件不复制)

030a7af559104ff5b6f993fe2605a930.png

7. 在上图空白处按着shift然后右键菜单 在此处打开power shell 运行得到如下结果 原因是缺少jvm.cfg 这是JVM虚拟机的配置文件 然后直接复制完整的jre的lib目录下的所有文件到自己精简的lib目录下

然后再次运行一次./java (值得注意的是 power shell的话 必须加上./ 才会从当前目录下找文件)

做完这些之后 应该是可以在这里运行你准备打包的jar文件的

在bin目录下新建一个批处理文件 内容如下

java -jar client.jar

pause

复制你的jar文件 在这里我的是client.jar

双击run.bat就可以 运行你的jar文件了 如果不行 就是jar文件的原因

2606fb0e14d7fbe6ab6882c6b16b04f4.png

8. 如果都可以了 那么 bin目录终于精简完了 TAT (打字好累)

#精简lib文件夹

1. 这里我做的比较水...我对lib文件夹不是太了解 所以精简的方法可能比较低级

2. 思路就是 上面不是可是已经能够运行jar文件了吗 那么 我们删除一个文件 就运行一次(这就是上面用批处理运行jar的原因 QAQ )

3. 主要是删除jar文件 从大到小 还可以尝试删除一些其他的文件 比如图片文件 字体文件 不过可能会引起一些bug

4.  这是我删除之后

b07743bcadfe81a124d21f6c43f7df6a.png

5. 这样的话 这是比较笨的方法 但是效果也还不错 然后我们发现 最大的就是rt.jar文件了 那么接下来就就是精简rt.jar

6. 拓展方法 我在看博客的时候发现可以从class.txt文件里面找到用到的jar文件 但是,,,并不能记录不是jar的文件  有些文件可能是配置文件 丢失了就不能用了 不过有人会的话 请在下面留言一下 我更新

#精简rt.jar文件

1. 记得上面的到的class.txt文件吗,把他复制到与你新建的jre目录下 也即是与bin和lib目录同目录 (这里是为了方便 不复制也行)

2. 现在 处理class.txt文件 用notepad++打开它 你会发现会有好多好多的东西TAT 我就被这个吓到了 但是没关系 接下来用notepad++的话 就会很简单

3. 删除掉所有的 不带方括号的行

4. Ctrl + F 然后搜索  "[Opened "   然后把所有带"[Opened "个的行删除掉 (是删除一整行)

5. Ctrl + F 然后搜索  "[Loaded "  点击计数,然后点击替换选项卡 全部替换 (替换的时候注意点一下计数,对比一下行数 应该是一样的,,,,)

6. 点击"正则表达式"的单选框 在查找目标里面填上正则表达式 点击计数,然后 替换->全部替换

2b0c9f2afb3116c829ea6a6d30e76c06.png

7.这样 我们就得到了如下的东西 保存

30fc358ae02a0bcdda916d0b64aa299e.png

8. jar文件本质上是zip文件 那么 我们把rt.jar文件复制到class.txt同一个目录 这样的话 精简的jre目录下就有 bin、lib、class.txt、rt.jar文件或文件夹了 然后右键 "解压到rt/" (我这里用的360压缩) 这样我么就得到了一个rt文件夹 里面是rt.jar的完整内容

9. 然后新建一个文件夹名字是ort文件夹 用来放需要的class文件

10. 然后执行如下代码 这些代码是复制别人博客的 再次非常感谢原作者 [https://blog.csdn.net/kkkwewewaqsdfas/article/details/11829349?t=1489849302000] :

记得修改第一行 package ch1;

另外 代码中的InputOutput那个会出错 因为缺少那个类 在上面原作者的链接里面可以找到InputOutput的java文件

原作者的 InputOutput文件里面的main()方法会出错 删除即可

2019年2月15补充: 如果不行折腾 以下代码已经编译成jar包 可以直接运行: 需求类复制工具 点击下载即可 运行就知道怎么用了

packagech1;

importjava.io.BufferedReader;importjava.io.File;importjava.io.FileInputStream;importjava.io.IOException;importjava.io.InputStreamReader;importjava.io.LineNumberReader;//import InputOutput;

/***@authorknowyourself1010

**/

public classCopyUsefulClasses {//文件拷贝

private static booleancopy(String sourceFileLocation,

String objectFileLocation, String fileName) {try //must try and catch,otherwise will compile error

{if (sourceFileLocation.substring(sourceFileLocation.length() - 1) != "/") {

sourceFileLocation+= "/";

}if ((objectFileLocation.substring(objectFileLocation.length() - 1)) != "/") {

objectFileLocation+= "/";

}

InputOutput inputOutput= newInputOutput();byte[] b =inputOutput

.DataOutputFully(sourceFileLocation, fileName);

inputOutput.DataInputFully(objectFileLocation, fileName, b);return true; //if success then return true

}catch(Exception e) {

System.out.println("Error!");return false; //if fail then return false

}

}//读取路径,copy

private static intdealClass(String needfile, String sdir, String odir)throwsIOException {int sn = 0; //成功个数

if (odir.length() > 0 && sdir.length() > 0) {if ((sdir.substring(sdir.length() - 1)) != "/") {

sdir+= "/";

}if (odir.substring(odir.length() - 1) != "/") {

odir+= "/";

}

File usedclass= newFile(needfile);if(usedclass.canRead()) {

String line= null;

LineNumberReader reader= newLineNumberReader(new InputStreamReader(newFileInputStream(usedclass),"UTF-8"));while ((line = reader.readLine()) != null) {

line=line.trim();if (line.contains(".") || line.contains("/")) {//format the direction from package name to path

String dir = line.replace(".", "/");//filter the file name.

String tmpdir = dir.substring(0, dir.lastIndexOf("/"));

String sourceFileLocation= sdir +tmpdir;

String objectFileLocation= odir +tmpdir;

String fileName=dir.substring(

dir.lastIndexOf("/") + 1, dir.length())+ ".class";

File fdir= newFile(objectFileLocation);if (!fdir.exists())

fdir.mkdirs();boolean copy_ok =copy(sourceFileLocation,

objectFileLocation, fileName);if(copy_ok)

sn++;else{

System.out.println(line);

}

}else{

sn= -1;

}

}

}

}returnsn;

}/***@paramargs*/

public static voidmain(String[] args) {//TODO Auto-generated method stub

try{

BufferedReader lineOfText= null;//get need classes log file direction

System.out

.println("要读取的class.txt文件的绝对路径 :");

lineOfText= new BufferedReader(newInputStreamReader(System.in));

String needfile=lineOfText.readLine();//get source folder direction

System.out

.println(needfile+ "\n输入jre/lib/rt.jar解压後的rt文件夹所在的路径 :");

lineOfText= new BufferedReader(newInputStreamReader(System.in));

String sdir=lineOfText.readLine();//get object folder direction

System.out

.println(sdir+ "\n再输入ort(所要存放拷贝过来的有用的.class文件的文件夹):");

lineOfText= new BufferedReader(newInputStreamReader(System.in));

String odir=lineOfText.readLine();

System.out.println(odir+ "\n");int sn =dealClass(needfile, sdir, odir);

System.out.print(sn);

}catch(IOException e) {//TODO 自动生成 catch 块

e.printStackTrace();

}

}

}

运行的时候填写这样的内容

bc2e27419874aed214d64504ebea3bfa.png

首先输入usedClasses.txt的绝对路径,回车,在输入jre/lib/rt.jar解压後的rt文件夹所在的路径,回车,再输入ort(所要存放拷贝过来的有用的.class文件的文件夹)。然后等上几分中,期间会提示,你的产品程序所用到的jre不包含的类不存在,不用管,因为我们呢只拷贝rt文件中的.class文件 (这一段话复制自上面代码所在博客)

11. 这样的话 在ort文件夹里面就有了很多文件夹 像是java、javax什么的 全选这些文件夹 右键 添加到 ort.zip

11.5: 将ort打包的方法还有一个 将cmd工作目录切换到 有[ort]文件夹的哪里 然后执行命令 [jar cvf rt.jar -C ort/ .] (方括号里面的全部内容) 即可 方法来自评论区:水瓶座鬼才

12. 得到ort.zip文件之后改名为rt.jar

13. 删除lib目录下的rt.jar文件 用上面的rt.jar文件(也就是我们自己打包的)替换

14. 在bin目录下运行run.bat文件 然后如果成功了就测试一下各种功能 确认没问题的话 jre环境就已经精简成功了 可以直接看下面的exe打包阶段了

15 如果有错误 应该是这样的 那么应该是这样的 这里的话 明显是class文件缺失

3707053d7c672791628f27b3ec30e61c.png

16. 在精简的rt.jar文件上面右键 用360压缩打开

17. 打开之前解压的rt.jar文件夹(完整的rt.jar文件解包之后的rt文件夹)

18. 根据上图中提示的丢失class文件的路径, 在360压缩窗口和rt文件夹中找到丢失的class文件 然后拖到360压缩窗口里 需要保证class文件的位置是一样的 (比如在rt文件夹里面的class文件路径是java/lang 目录下 那么在360压缩里也应该是这个目录)如果添加出错 那就关闭上图的窗口

19.  再运行bin目录下的run.bat批处理文件 可能还会有错 有错的话 就继续上一个步骤 直到没有错误

20. 这样的话 jre环境就已经精简成功了 : ) 接下来就是打包成exe了

#打包成exe

1. 这个就比较简单了 使用现成的工具就可以了 就是      winrar

2. 不过呢 这个软件似乎是没有执行命令行的作用的 解决方法就是用C语言写一个启动器 QAQ  (其他语言也行 只要是个exe就行了) 但是呢 直接用C语言执行 java -jar client.jar 这个命令会有一个问题 就是会有一个控制台窗口 (我这里是图形界面 如果没有图形界面的话 那就不用考虑了)  这个据说用javaw 运行就没问题 不会出现控制台窗口 但是我失败了/QAQ 不知道为啥 所以接下来需要这样做

3. 编译一个exe文件 C语言代码如下  说明一下 C语言如果是控制台程序的话 运行的时候还是有控制台窗口的 所有建立的工程是win32工程 也就是默认带窗口的那种 如果有小伙伴不知道怎么弄 请在下面留言 我会补充一下

#include "stdafx.h"#include"无窗口的vbs运行.h"

intAPIENTRY _tWinMain(_In_ HINSTANCE hInstance,

_In_opt_ HINSTANCE hPrevInstance,

_In_ LPTSTR lpCmdLine,

_In_intnCmdShow)

{

system("run.vbs");return 0;

}

核心代码就是是system("run.vbs");

4. 那么接下来就编写run.vbs 内容如下 作用是运行一个名为run.bat的批处理 并且把窗口隐藏起来

Set ws = CreateObject("Wscript.Shell")

ws.run"cmd /c run.bat",vbhide

5. 修改bin目录下的run.bat文件 修改内容如下 然后复制到与bin、lib文件夹同目录

cd bin

java-jar client.jar

6. 上面两步完成了GUI界面Java程序 隐藏控制台窗口运行 然后把上面编译的启动器exe放在与bin、lib文件夹同目录 最终是这样的 双击run.vbs或者启动器.exe应该都是可以无控制台窗口运行的

b41744343c23271e82b3e0e7a24f5af6.png

7. 终于到了最终打包的时候了 TAT  下载winrar 安装

8. 全选上图所有的文件及文件夹 压缩为rar格式的压缩包

9. 用winrar打开rar压缩包 然后选择自解压格式

df1331f19fd4c7d856af4344f641b680.png

11c40effd8021f7848b8f88e2fc33f50.png

90a8ef619e22ab5690e864a89e53c72d.png

10. 然后点击确定 再点确定 就可以得到 在上图高级设置里面还可以修改生成exe的图标

ecf0f45abd583325e76beb3cb67e2e05.png

看到了吗 整个环境加上 jar打包成exe之后只有11MB 不到了

最终  双击运行一下 TAT 惊喜的发现 成功了!!!!!!!!!!!!!!!!!!!!!!!!!!

如果不能打包成功 请打开  https://blog.csdn.net/fz835304205/article/details/46942589

可以看看这个博文 谢谢这位博主分享经验 ^_^

#期间可能遇到的问题

1. class文件丢失太多了 这个主要是在生成class.txt文件的时候没有把所有程序功能使用一遍造成的 所谓的使用包括点击窗口 以及各个组件的功能

2. 在往rt.jar文件里面添加class文件的时候添加不进去 这个可能是因为你的程序还在运行 需要关闭控制台窗口

3. 有时候可能往rt.jar里面添加class文件也不能解决问题 那么就把相关的整个文件夹替换进去

4. 完成之后你的程序可能会有各种bug那么 你得让控制台窗口出来 然后查看异常 看看丢失了那个class文件 把他 添加到rt.jar中相同的文件夹下

5. 打包完了发现不能双击运行提示丢失DLL文件 那么 你得安装运行库 百度运行库合集就可以了

6. 这样精简的jre对其他系统(win7 winxp)的兼容性比较差 甚至不能运行 解决方案就是在目标系统上运行一次 得到class.txt 整合所有用到的class文件应该就可以了(其实我这个没有尝试 是个思路)

7. 如果还有问题请在下方留言 有建议也请留言 谢谢 : )

感谢以下几篇文章:

https://blog.csdn.net/kkkwewewaqsdfas/article/details/11829349?t=1489849302000

https://blog.csdn.net/xiaoping8411/article/details/6973887

https://blog.csdn.net/ema1995cylove/article/details/52792361

https://blog.csdn.net/fz835304205/article/details/46942589 (winrar打包方式)

还有几个没收藏 谢谢了 ^_^

-------转发请写明出处 谢谢



推荐阅读
  • 如何实现织梦DedeCms全站伪静态
    本文介绍了如何通过修改织梦DedeCms源代码来实现全站伪静态,以提高管理和SEO效果。全站伪静态可以避免重复URL的问题,同时通过使用mod_rewrite伪静态模块和.htaccess正则表达式,可以更好地适应搜索引擎的需求。文章还提到了一些相关的技术和工具,如Ubuntu、qt编程、tomcat端口、爬虫、php request根目录等。 ... [详细]
  • 2016 linux发行版排行_灵越7590 安装 linux (manjarognome)
    RT之前做了一次灵越7590黑苹果炒作业的文章,希望能够分享给更多不想折腾的人。kawauso:教你如何给灵越7590黑苹果抄作业​zhuanlan.z ... [详细]
  • Webpack5内置处理图片资源的配置方法
    本文介绍了在Webpack5中处理图片资源的配置方法。在Webpack4中,我们需要使用file-loader和url-loader来处理图片资源,但是在Webpack5中,这两个Loader的功能已经被内置到Webpack中,我们只需要简单配置即可实现图片资源的处理。本文还介绍了一些常用的配置方法,如匹配不同类型的图片文件、设置输出路径等。通过本文的学习,读者可以快速掌握Webpack5处理图片资源的方法。 ... [详细]
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • 本文介绍了Linux Shell中括号和整数扩展的使用方法,包括命令组、命令替换、初始化数组以及算术表达式和逻辑判断的相关内容。括号中的命令将会在新开的子shell中顺序执行,括号中的变量不能被脚本余下的部分使用。命令替换可以用于将命令的标准输出作为另一个命令的输入。括号中的运算符和表达式符合C语言运算规则,可以用在整数扩展中进行算术计算和逻辑判断。 ... [详细]
  • Java在运行已编译完成的类时,是通过java虚拟机来装载和执行的,java虚拟机通过操作系统命令JAVA_HOMEbinjava–option来启 ... [详细]
  • 本文介绍了Swing组件的用法,重点讲解了图标接口的定义和创建方法。图标接口用来将图标与各种组件相关联,可以是简单的绘画或使用磁盘上的GIF格式图像。文章详细介绍了图标接口的属性和绘制方法,并给出了一个菱形图标的实现示例。该示例可以配置图标的尺寸、颜色和填充状态。 ... [详细]
  • HTML5网页模板怎么加百度统计?
    本文介绍了如何在HTML5网页模板中加入百度统计,并对模板文件、css样式表、js插件库等内容进行了说明。同时还解答了关于HTML5网页模板的使用方法、表单提交、域名和空间的问题,并介绍了如何使用Visual Studio 2010创建HTML5模板。此外,还提到了使用Jquery编写美好的HTML5前端框架模板的方法,以及制作企业HTML5网站模板和支持HTML5的CMS。 ... [详细]
  • 统一知识图谱学习和建议:更好地理解用户偏好
    本文介绍了一种将知识图谱纳入推荐系统的方法,以提高推荐的准确性和可解释性。与现有方法不同的是,本方法考虑了知识图谱的不完整性,并在知识图谱中传输关系信息,以更好地理解用户的偏好。通过大量实验,验证了本方法在推荐任务和知识图谱完成任务上的优势。 ... [详细]
  • 如何实现JDK版本的切换功能,解决开发环境冲突问题
    本文介绍了在开发过程中遇到JDK版本冲突的情况,以及如何通过修改环境变量实现JDK版本的切换功能,解决开发环境冲突的问题。通过合理的切换环境,可以更好地进行项目开发。同时,提醒读者注意不仅限于1.7和1.8版本的转换,还要适应不同项目和个人开发习惯的需求。 ... [详细]
  • 开发笔记:spring boot项目打成war包部署到服务器的步骤与注意事项
    本文介绍了将spring boot项目打成war包并部署到服务器的步骤与注意事项。通过本文的学习,读者可以了解到如何将spring boot项目打包成war包,并成功地部署到服务器上。 ... [详细]
  • loader资源模块加载器webpack资源模块加载webpack内部(内部loader)默认只会处理javascript文件,也就是说它会把打包过程中所有遇到的 ... [详细]
  • Jmeter对RabbitMQ压力测试
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了Jmeter对RabbitMQ压力测试相关的知识,希望对你有一定的参考价值。Jm ... [详细]
author-avatar
LordHo
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有