您可以使用Pack200文件而无需首先解压缩它?
是否有可能从Pack200创建的pack.gz文件中即时加载类(在内存中),而无需首先将其解压缩回jar中?我可以找到的所有示例都向我展示了如何将其解压缩为.jar文件,然后从.jar文件加载类。您可以使用Pack200文件而无需首先解压缩它?
是的,这是可能的。 Pack200.Unpacker.unpack方法写入JarOutputStream;如果您在后台线程中这样做,则可以使用管道将新的JarOutputStream连接到JarInputStream,然后从中读取。
public JarInputStream readPackFile(Path packGzFile)
throws IOException {
PipedInputStream pipeIn = new PipedInputStream();
PipedOutputStream pipeOut = new PipedOutputStream(pipeIn);
ExecutorService executor = Executors.newSingleThreadExecutor();
Callable<Void> unpacker = new Callable<Void>() {
@Override
public Void call()
throws IOException {
try (InputStream file =
new GZIPInputStream(
new BufferedInputStream(
Files.newInputStream(packGzFile)));
JarOutputStream jarOutput = new JarOutputStream(pipeOut)) {
Pack200.newUnpacker().unpack(file, jarOutput);
return null;
} finally {
executor.shutdown();
}
}
};
executor.submit(unpacker);
return new JarInputStream(pipeIn);
}
这应该足够了。但是,仍然存在两个问题:
- 如果解包操作出现错误,您将永远不会知道它,因为ExecutorServices会抑制它们的任务'异常。
- JarInputStream和JarOutputStream(更具体地说,它们的超类,InflaterInputStream和DeflaterOutputStream)不适用于管道。这是因为关闭JarOutputStream强制调用其finish()方法,但管道另一侧的JarInputStream将永远不会读取该数据。这意味着在调用
finish()
之前几乎肯定会关闭JarInputStream,导致finish()
由于管道损坏而生成IOException。
要解决第一个问题,我们可以重写JarInputStream的close
方法来解决解包操作中的任何故障。要解决第二,我们可以在覆盖的JarOutputStream到finish()
什么都不做:
public JarInputStream readPackFile(Path packGzFile)
throws IOException {
PipedInputStream pipeIn = new PipedInputStream();
PipedOutputStream pipeOut = new PipedOutputStream(pipeIn);
class NonFinishingJarOutputStream
extends JarOutputStream {
NonFinishingJarOutputStream(OutputStream out)
throws IOException {
super(out);
}
@Override
public void finish()
throws IOException {
// Deliberately empty.
}
}
ExecutorService executor = Executors.newSingleThreadExecutor();
Callable<Void> unpacker = new Callable<Void>() {
@Override
public Void call()
throws IOException {
try (InputStream file =
new GZIPInputStream(
new BufferedInputStream(
Files.newInputStream(packGzFile)));
JarOutputStream jarOutput =
new NonFinishingJarOutputStream(pipeOut)) {
Pack200.newUnpacker().unpack(file, jarOutput);
return null;
} finally {
executor.shutdown();
}
}
};
Future<?> unpackerTask = executor.submit(unpacker);
return new JarInputStream(pipeIn) {
@Override
public void close()
throws IOException {
super.close();
try {
// If the unpack generated an exception, propagate it here.
unpackerTask.get();
} catch (ExecutionException e) {
throw new IOException(e);
} catch (InterruptedException e) {
InterruptedIOException iie = new InterruptedIOException();
iie.initCause(e);
throw iie;
}
}
};
}
这给了我一个JarInputStream,而不是JarFile。 https://stackoverflow.com/questions/16602668/creating-a-classloader-to-load-a-jar-file-from-a-byte-array似乎表明,实际上很难用JarInputStream做很多事情。 –
所有JarFile构造函数都需要一个文件。我很确定没有办法使用JarFile类没有一个。 – VGR
是的,这是经常与JWS完成。 – EJP