2017-10-29 62 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

相關問題