热门标签 | 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打包方式)

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

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



推荐阅读
  • Week04面向对象设计与继承学习总结及作业要求
    本文总结了Week04面向对象设计与继承的重要知识点,包括对象、类、封装性、静态属性、静态方法、重载、继承和多态等。同时,还介绍了私有构造函数在类外部无法被调用、static不能访问非静态属性以及该类实例可以共享类里的static属性等内容。此外,还提到了作业要求,包括讲述一个在网上商城购物或在班级博客进行学习的故事,并使用Markdown的加粗标记和语句块标记标注关键名词和动词。最后,还提到了参考资料中关于UML类图如何绘制的范例。 ... [详细]
  • Java程序设计第4周学习总结及注释应用的开发笔记
    本文由编程笔记#小编为大家整理,主要介绍了201521123087《Java程序设计》第4周学习总结相关的知识,包括注释的应用和使用类的注释与方法的注释进行注释的方法,并在Eclipse中查看。摘要内容大约为150字,提供了一定的参考价值。 ... [详细]
  • 颜色迁移(reinhard VS welsh)
    不要谈什么天分,运气,你需要的是一个截稿日,以及一个不交稿就能打爆你狗头的人,然后你就会被自己的才华吓到。------ ... [详细]
  • 20209测试通过:eclipse安装svn插件
    网址不能用了,新的办法参考:https:quantum6.blog.csdn.netarticledetails117250800下载了最新的ecli ... [详细]
  • java io换行符_Java IO:为什么从stdin读取时,换行符的数字表示出现在控制台上?...
    只是为了更好地理解我在讲座中听到的内容(关于Java输入和输出流),我自己做了这个小程序:publicstaticvoidmain(String[]args)thro ... [详细]
  • 刚开始crousera上学习<algorithmspart1>但对JAVA实在是不熟。******************************************** ... [详细]
  • 本文介绍了一些好用的搜索引擎的替代品,包括网盘搜索工具、百度网盘搜索引擎等。同时还介绍了一些笑话大全、GIF笑话图片、动态图等资源的搜索引擎。此外,还推荐了一些迅雷快传搜索和360云盘资源搜索的网盘搜索引擎。 ... [详细]
  • 也就是|小窗_卷积的特征提取与参数计算
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了卷积的特征提取与参数计算相关的知识,希望对你有一定的参考价值。Dense和Conv2D根本区别在于,Den ... [详细]
  • 猜字母游戏
    猜字母游戏猜字母游戏——设计数据结构猜字母游戏——设计程序结构猜字母游戏——实现字母生成方法猜字母游戏——实现字母检测方法猜字母游戏——实现主方法1猜字母游戏——设计数据结构1.1 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 本文介绍了一个题目的解法,通过二分答案来解决问题,但困难在于如何进行检查。文章提供了一种逃逸方式,通过移动最慢的宿管来锁门时跑到更居中的位置,从而使所有合格的寝室都居中。文章还提到可以分开判断两边的情况,并使用前缀和的方式来求出在任意时刻能够到达宿管即将锁门的寝室的人数。最后,文章提到可以改成O(n)的直接枚举来解决问题。 ... [详细]
  • 3.223.28周学习总结中的贪心作业收获及困惑
    本文是对3.223.28周学习总结中的贪心作业进行总结,作者在解题过程中参考了他人的代码,但前提是要先理解题目并有解题思路。作者分享了自己在贪心作业中的收获,同时提到了一道让他困惑的题目,即input details部分引发的疑惑。 ... [详细]
  • Ihavethefollowingonhtml我在html上有以下内容<html><head><scriptsrc..3003_Tes ... [详细]
  • 使用eclipse创建一个Java项目的步骤
    本文介绍了使用eclipse创建一个Java项目的步骤,包括启动eclipse、选择New Project命令、在对话框中输入项目名称等。同时还介绍了Java Settings对话框中的一些选项,以及如何修改Java程序的输出目录。 ... [详细]
  • Hibernate延迟加载深入分析-集合属性的延迟加载策略
    本文深入分析了Hibernate延迟加载的机制,特别是集合属性的延迟加载策略。通过延迟加载,可以降低系统的内存开销,提高Hibernate的运行性能。对于集合属性,推荐使用延迟加载策略,即在系统需要使用集合属性时才从数据库装载关联的数据,避免一次加载所有集合属性导致性能下降。 ... [详细]
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社区 版权所有