Jre瘦身
来源:互联网 发布:linux压缩命令 编辑:程序博客网 时间:2024/05/15 23:53
Jre瘦身
1. bin瘦身
启动运行的程序,这里我以自己开发的源码统计工具作为例子进行讲解:
这是主界面
第二步:就是找到加载这个进程的DLL文件,打开360安全卫士à功能大全à进程管理器找到刚才的进程,并且单击显示加载此进程的dll文件。
如下:
将其中的dll文件拷贝到新建的bin目录下,其中有一个client文件夹直接拷贝,另外有一个java.exe是必须的,具体目录如下图:
2. 对lib文件进行瘦身
通过在命令行执行如下语句:
java -jar -verbose:class CodeTongJi.jar>>Class.txt
然后在软件中操作所有的功能,让他尽可能的加载有关的类。产生的Class.txt文件内容如下:
[Loaded java.lang.Object from shared objects file]
[Loaded java.io.Serializable from shared objects file]
[Loaded java.lang.Comparable from shared objects file]
[Loaded java.lang.CharSequence from shared objects file]
[Loaded java.lang.String from shared objects file]
[Loaded java.lang.reflect.GenericDeclaration from shared objects file]
[Loaded java.lang.reflect.Type from shared objects file]
[Loaded java.lang.reflect.AnnotatedElement from shared objects file]
[Loaded java.lang.Class from shared objects file]
……
对此进行处理【可以使用editplus进行处理】,得到如下的文件
java/lang/Object
java/io/Serializable
java/lang/Comparable
java/lang/CharSequence
java/lang/String
java/lang/reflect/GenericDeclaration
java/lang/reflect/Type
java/lang/reflect/AnnotatedElement
….
接下来写个程序,然后根据这样的表单去查找相关的.class文件,然后拷贝到制定的文件夹中,以下是从网上找来的,并且修改了一下,以便符合实际应用的需要,详细请见在test包下的CopyClass类:
package com.cgx;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
/**
* 由于class.txt每行都是形同: [Loaded java.lang.System from shared objects
* file]的一串字符,修改文本以方便获取类完整名java.lang.System,从而获得类似类路径java/lang/System的一串字符,方便后继编写类拷贝程序.
* 修改方法:
* 1.查找并替换[Loaded 为空,达到删除[Loaded 的目的.
* 2.使用任意一个具有正则表达式查找替换功能的文本编辑器,查找并替换from.*为空,达到删除 from及其后面的字符串的目的.
* 3.查找并替换.为/
* 4.删除以[Opened 开头的行.
* 5.删除程序中System.out.println的输出行.
* 首先是输出这样的class.txt文件
* 通过命令行执行
* java -jar -verbose:class D:\BillSysGDB\toolsLBMS\toolsLBMS_Browser_tool.jar >>class.txt
* 即可得到class.txt文件中的内容
* 提取之后的文件为class_success.txt
* @author chenguixin
* 2012-7-27 下午02:17:51
* CopyClass.java
*/
public class CopyClass {
private String source = "D:\\lib\\"; // 类源目录
private String dest = "D:\\lib\\"; // 类拷贝目的目录
String[] jarArr = new String[] { "rt", "charsets" };
/***
*
* @param source
* 类源目录
* @param dest
* 类拷贝目的目录
* @param jarArr
* 需要的提取的jar文件
*/
public CopyClass(String source, String dest, String[] jarArr) {
this.source = source;
this.dest = dest;
this.jarArr = jarArr;
}
public void obtainClassPath(String sourceName, String destName) {
try {
File sourceFile = new File(sourceName);
FileInputStream fi = new FileInputStream(sourceFile);
InputStreamReader ir = new InputStreamReader(fi);
BufferedReader br = new BufferedReader(ir);
File destFile = new File(destName);
PrintWriter pw = new PrintWriter(destFile);
String content = br.readLine();
StringBuffer writer = new StringBuffer();
while (content != null) {
// 去掉两边空格
content = content.trim();
if (content.indexOf("[Loaded") != -1
&& content.indexOf("file:/D:/BillSysGDB/toolsLBMS/") == -1) {
int begin = 7;
int end = content.indexOf(" from ");
if (end == -1) {
content = br.readLine();
continue;
}
System.err.println();
System.err.println(content);
System.err.println("content->begin:" + begin + ";end:"
+ end);
System.err.println();
content = content.substring(begin, end).trim();
content = content.replaceAll("\\.", "\\/");
// if (content.indexOf("$") == -1) {
writer.append(content + "\r\n");
// }
// pw.println(content) ;//输入文件中
content = br.readLine();
} else {
content = br.readLine();
}
}
pw.println(writer.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
String[] jarArr = new String[]{"rt","charsets"};
CopyClass obj = new CopyClass("D:\\lib\\","D:\\lib\\",jarArr);
obj.readAndCopy("D:\\BillSysGDB\\toolsLBMS\\class_success.txt");
// obj.obtainClassPath("D:\\BillSysGDB\\toolsLBMS\\logg.txt",
// "D:\\BillSysGDB\\toolsLBMS\\class_success.txt");
}
/***
* @param logName
* 提取class明细
*/
public void readAndCopy(String logName) {
int count = 0; // 用于记录成功拷贝的类数
try {
FileInputStream fi = new FileInputStream(logName);
InputStreamReader ir = new InputStreamReader(fi);
BufferedReader br = new BufferedReader(ir);
String string = br.readLine();
string = string.trim() ;
while (string != null) {
if(!"".equals(string)){
if (copyClass(string) == true)
count++;
else
System.out.println("ERROR " + count + ": " + string);
}
string = br.readLine();
if(string != null)
string = string.trim() ;
}
} catch (IOException e) {
System.out.println("ERROR: " + e);
}
System.out.println("count: " + count);
}
/***
* 从原jar路径提取相应的类到目标路径,如将java/lang/CharSequence类从rt目录提取到rt1目录
*
* @param string
* 提取类的全路径
* @return
* @throws IOException
*/
public boolean copyClass(String string) throws IOException {
System.err.println(string) ;
String classDir = string.substring(0, string.lastIndexOf("/"));
String className = string.substring(string.lastIndexOf("/") + 1, string
.length())
+ ".class";
boolean result = false;
for (String jar : jarArr) {
File srcFile = new File(source + "/" + jar + "/" + classDir + "/"
+ className);
if (!srcFile.exists()) {
continue;
}
byte buf[] = new byte[256];
FileInputStream fin = new FileInputStream(srcFile);
/* 目标目录不存在,创建 */
File destDir = new File(dest + "/" + jar + "1/" + classDir);
if (!destDir.exists())
destDir.mkdirs();
File destFile = new File(destDir + "/" + className);
FileOutputStream fout = new FileOutputStream(destFile);
int len = 0;
while ((len = fin.read(buf)) != -1) {
fout.write(buf, 0, len);
}
fout.flush();
result = true;
break;
}
return result;
}
}
执行后得到这样的文件:charsets1和rt1文件
对这两个文件进行压缩成jar文件
打包后替换掉在lib下的charsets和rt两个包
至此瘦身完成
注意:在瘦身过程中,一定要注意不能缺少类,要尽可能的然其加载所有的类,否则很容报错,对此可以使用eclipse中添加自己的环境,然后进行测试。^__^
补充:如果执行exe程序无法启动时可以从以下三个方面进行查找原因
1. 使用eclipse添加自己瘦身后的jre环境,查找缺少的class文件
2. 在eclipse上可以运行,不代表在单机版下可以运行,因为瘦身后,可能存在一些类是不存在的,会导致jar可执行包和exe可执行文件无法执行,接下来一步是使用的自己瘦身后的jre环境来执行jar包,看看是否有异常报出,例子如下:
java -jar D:\temp\CodeTongJi\CodeTongJi.jar
3. 完成第二步之后并不是代表就可以执行exe文件,虽然可以在自己瘦身后的环境中可以执行jar,但是exe可能还会有异常报出,如何处理,此时关键的问题是,执行exe时能够报出异常,并打印出来,下面是我想到的一个方面,通过Runtime类执行一个命令,返回来一个进程对象,将该进程对象的ErrorInputStream打印出来,例子如下,详细请见在test包下的TestExe类:
package com.cgx;
import java.io.FileInputStream;
import java.io.IOException;
public class TestExe {
/**
*
* @author chenguixin
* @Created On 2012-8-2 下午02:59:46
* TestExe.java
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Process process = null ;
try {
process = Runtime.getRuntime().exec("D:\\temp\\CodeTongJi\\CodeTongJi.exe") ;
FileInputStream fis =(FileInputStream) process.getErrorStream() ;
int word = 0 ;
while((word = fis.read())!=-1){
System.err.print((char)word) ;
}
System.err.println(process.getErrorStream().read()) ;
System.err.println(process.getOutputStream()) ;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
4. 需要在不同的机器上去测试
- jre瘦身
- Jre瘦身
- jre瘦身记
- JRE瘦身心得
- 整理JRE瘦身或精简JRE
- 整理JRE瘦身或精简JRE
- 整理JRE瘦身或精简JRE
- 整理JRE瘦身或精简JRE
- 整理JRE瘦身或精简JRE
- 整理JRE瘦身或精简JRE
- 瘦身
- 瘦身
- Windows 瘦身
- flex 瘦身
- 瘦身笔记
- 瘦身润乾补全记
- 系统瘦身
- win7瘦身
- 山大计算机学院教师讲案之一外键
- 带宽计算方法 及 大B与小b 说明
- Qt4.8.2 托盘
- 开发Android应用程序时改变了图标,但是重新启动依旧是默认的图标
- 单例2
- Jre瘦身
- SEVERE: org.apache.solr.common.SolrException: undefined field text
- 1. Uboot 简介
- 过来人对于在校生找工作的一点看法 很有感触!
- 为何C语言(的函数调用)需要堆栈,而汇编语言却不需要堆栈(转载)
- POJ 1915 Knight Moves (经典的BFS) --from lanshui_Yang
- 转android-Service和Thread的区别
- 在Xcode中使用C++与Objective-C混编
- 在TabActivity中如何添加BACK键响应