Pack200에 의해 생성 된 pack.gz 파일에서 (메모리에) 클래스를 처음으로 병에 압축을 풀지 않고도로드 할 수 있습니까? 모든 예제는 .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
방법을 대체 할 수 있습니다, 첫 번째 문제를 해결하려면. 예
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;
}
}
};
}
JarFile이 아니라 JarInputStream을 제공합니다. https://stackoverflow.com/questions/16602668/creating-a-classloader-to-load-a-jar-file-from-a-byte-array는 실제로 JarInputStream을 사용하여 실제로 많은 작업을 수행하는 것이 어렵다는 것을 나타내는 것 같습니다. . –
모든 JarFile 생성자에는 파일이 필요합니다. 나는 JarFile 클래스를 사용하지 않는 방법이 없다고 확신한다. – VGR
, 이것은 일상적으로 JWS 이루어집니다 : 두 번째를 해결하기 위해, 우리는 아무것도하지 않고하는 JarOutputStream에
finish()
을 대체 할 수 있습니다. – EJP