分享
 
 
 

怎样制作自解压的jar文件

王朝厨房·作者佚名  2007-01-04
窄屏简体版  字體: |||超大  

这是一篇描述怎样制作自解压jar文件的文章,作者通过自己编写的一个自解压程序,并把这个自解压程序以及一个manifest文件一起加入原始的jar文件中,就制作出一个可以在各种支持java的平台上运行的自解压的jar 文件。

自解压文件

我们先来了解一下自解压文件,在window下可以用自解压制作工具如winzip self-Extractor来制作自解压文件,这些工具会把一个zip文件与解压程序打包在一起而产生一个新的可执行文件。然后只要运行这个可执行文件,就可以把zip文件中的内容解开。那为什么要创建自解压jar文件呢,创建成自解压zip文件不就好了?我们应该注意到自解压jar文件可以在任意支持java的平台上解开并执行,例如,可以在linux下执行。创建jar自解压文件很简单,只需要一个特殊的JAR manifest文件、一个基于java的解压程序(这个程序是原作者写的)、包含基本文件的jar 或者zip文件以及任何jsdk的jar应用程序

manifest文件

要生成可执行jar文件,需要在META-INF 目录下的manifest文件,文件名为:MANIFEST.MF ,但在我们这里我们只需要在文件中指定在这个基于java 的解压程序中包含main()的类的名称:Main-Class: ZipSelfExtractor

我们已经把一个叫做jarmanifest的文件加入到这个技巧的源程序包中。

解压程序

你可以用各种方法来实现这个解压程序,在我们这里使用了一个简单直接的办法。首先,解压程序判断这个自解压jar文件的名称,有了这个文件名,解压程序使用解压标准,把文件解开。具体的可以查看在源码包中的ZipSelfExtractor.java文件。

值得一提的是这里用了一个很巧妙的办法获取jar文件的文件名,虽然在命令行中出现的这个文件的名字,但它并没有作为参数传入类的main()中,因此,这里使用了以下的代码来获取文件名:

private String getJarFileName ()

{

myClassName = this.getClass().getName() + ".class";

URL urlJar =

this.getClass().getClassLoader().getSystemResource(myClassName);

String urlStr = urlJar.toString();

int from = "jar:file:".length();

int to = urlStr.indexOf("!/");

return urlStr.substring(from, to);

}

请注意:getSystemResource() 中使用了myClassName而不是ZipSelfExtractor.class作参数,这使得我们可以更改加压程序的名字而不需要修改代码。

接下来,我们来分析获得这个jar文件的名字。首先,可以获取指向包含正在运行类的文件,urlStr = urlJar.toString();有了这个url,把jar文件名去掉,剩下的就是我们想要的,下面是这个url的格式:

jar:file:/home/test/zipper.jar!/ZipSelfExtractor.class

有了文件名,就可以开始解压,详细的解压算法请大家自己看源码。

为了可以更方便实用,程序使用了图形界面,程序中使用了JFileChooser类可以选择要解压的目标目录。

最后程序还确保不把这两个文件:manifest文件和extractor’s .class(在我们这里是ZipSelfExtractor.class)文件也解出来,程序是用来解开原始的jar的内容,而这两个文件并属于jar原始内容。

打包jar文件

有了manifest文件与解压程序,我们就可以创建自解压jar文件了,以下是一个例子:

1.创建一个zip文件Myzip.zip

2.下载zipper.jar

3.把文件解到当前目录,准备制作自解压jar文件

java -jar zipper.jar

4.把zipper.class拷贝成 ZipSelfExtractor.class

5.把 myzip.zip 重命名为 myzip.jar

6.把myzip.jar中的内容替换为jarmanifest和ZipSelfExtractor.class这两个文件

jar uvfm myzip.jar jarmanifest ZipSelfExtractor.class

7.执行java -jar myzip.jar就可以看到效果了,试试看

后记

一个自解压的jar文件能够很好的跨平台使用,自解压jar文件创建简单,只需要有jre1.2或或者更新的版本就可以实现了。

附自解压程序的源代码:

/* ZipSelfExtractor.java */

/* Author: Z.S. Jin

Updates: John D. Mitchell */

import java.io.*;

import java.net.*;

import javax.swing.*;

import java.util.zip.*;

import java.util.*;

import java.text.*;

public class ZipSelfExtractor extends JFrame

{

private String myClassName;

static String MANIFEST = "META-INF/MANIFEST.MF";

public static void main(String[] args)

{

ZipSelfExtractor zse = new ZipSelfExtractor();

String jarFileName = zse.getJarFileName();

zse.extract(jarFileName);

System.exit(0);

}

ZipSelfExtractor()

{

}

private String getJarFileName()

{

myClassName = this.getClass().getName() + ".class";

URL urlJar = this.getClass().getClassLoader().getSystemResource(myClassName);

String urlStr = urlJar.toString();

int from = "jar:file:".length();

int to = urlStr.indexOf("!/");

return urlStr.substring(from, to);

}

public void extract(String zipfile)

{

File currentArchive = new File(zipfile);

JFileChooser fc = new JFileChooser();

fc.setCurrentDirectory(new File("."));

fc.setDialogType(JFileChooser.OPEN_DIALOG);

fc.setDialogTitle("Select destination directory for extracting " +

currentArchive.getName());

fc.setMultiSelectionEnabled(false);

fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);

if (fc.showDialog(ZipSelfExtractor.this, "Select")

!= JFileChooser.APPROVE_OPTION)

{

return; //only when user select valid dir, it can return approve_option

}

File outputDir = fc.getSelectedFile();

byte[] buf = new byte[1024];

SimpleDateFormat formatter = new SimpleDateFormat ("MM/dd/yyyy hh:mma",Locale.getDefault());

ProgressMonitor pm = null;

boolean overwrite = false;

ZipFile zf = null;

FileOutputStream out = null;

InputStream in = null;

try

{

zf = new ZipFile(currentArchive);

int size = zf.size();

int extracted = 0;

pm = new ProgressMonitor(getParent(), "Extracting files...", "starting", 0, size-4);

pm.setMillisToDecideToPopup(0);

pm.setMillisToPopup(0);

Enumeration entries = zf.entries();

for (int i=0; i<size; i++)

{

ZipEntry entry = (ZipEntry) entries.nextElement();

if(entry.isDirectory())

continue;

String pathname = entry.getName();

if(myClassName.equals(pathname) || MANIFEST.equals(pathname.toUpperCase()))

continue;

extracted ++;

pm.setProgress(i);

pm.setNote(pathname);

if(pm.isCanceled())

return;

in = zf.getInputStream(entry);

File outFile = new File(outputDir, pathname);

Date archiveTime = new Date(entry.getTime());

if(overwrite==false)

{

if(outFile.exists())

{

Object[] options = {"Yes", "Yes To All", "No"};

Date existTime = new Date(outFile.lastModified());

Long archiveLen = new Long(entry.getSize());

String msg = "File name conflict: "

+ "There is already a file with "

+ "that name on the disk!\n"

+ "\nFile name: " + outFile.getName()

+ "\nExisting file: "

+ formatter.format(existTime) + ", "

+ outFile.length() + "Bytes"

+ "\nFile in archive:"

+ formatter.format(archiveTime) + ", "

+ archiveLen + "Bytes"

+"\n\nWould you like to overwrite the file?";

int result = JOptionPane.showOptionDialog(ZipSelfExtractor.this,

msg, "Warning", JOptionPane.DEFAULT_OPTION,

JOptionPane.WARNING_MESSAGE, null, options,options[0]);

if(result == 2) // No

{

continue;

}

else if( result == 1) //YesToAll

{

overwrite = true;

}

}

}

File parent = new File(outFile.getParent());

if (parent != null && !parent.exists())

{

parent.mkdirs();

}

out = new FileOutputStream(outFile);

while (true)

{

int nRead = in.read(buf, 0, buf.length);

if (nRead <= 0)

break;

out.write(buf, 0, nRead);

}

out.close();

outFile.setLastModified(archiveTime.getTime());

}

pm.close();

zf.close();

getToolkit().beep();

JOptionPane.showMessageDialog

(ZipSelfExtractor.this,

"Extracted " + extracted +

" file" + ((extracted > 1) ? "s": "") +

" from the\n" +

zipfile + "\narchive into the\n" +

outputDir.getPath() +

"\ndirectory.",

"Zip Self Extractor",

JOptionPane.INFORMATION_MESSAGE);

}

catch (Exception e)

{

System.out.println(e);

if(zf!=null) { try { zf.close(); } catch(IOException ioe) {;} }

if(out!=null) { try {out.close();} catch(IOException ioe) {;} }

if(in!=null) { try { in.close(); } catch(IOException ioe) {;} }

}

}

}

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有