2017-10-29 92 views

回答

0

是的,这是可能的。 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; 
      } 
     } 
    }; 
} 
+0

这给了我一个JarInputStream,而不是JarFile。 https://stackoverflow.com/questions/16602668/creating-a-classloader-to-load-a-jar-file-from-a-byte-array似乎表明,实际上很难用JarInputStream做很多事情。 –

+1

所有JarFile构造函数都需要一个文件。我很确定没有办法使用JarFile类没有一个。 – VGR

相关问题