奈何建造自解压的jar文件
副标题#e#
这是一篇描写奈何建造自解压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原始内容。
#p#副标题#e#
打包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) {;} }
}
}
}