2016-01-13 65 views
0

我有一個OutputStream,可以初始化爲一個OutputStreams鏈。可以有任何級別的鏈接。唯一保證的是在鏈的末尾是一個FileOutputStream。我如何重新創建一個只有filename修改的鏈式OutputStream

我需要在FileOutputStream中使用修改過的Filename重新創建此鏈接的​​outputStream。如果out變量(存儲底層鏈接的outputStream)是可訪問的,這將是可能的;如下所示。

public OutputStream recreateChainedOutputStream(OutputStream os) throws IOException { 
    if(os instanceof FileOutputStream) { 
     return new FileOutputStream("somemodified.filename"); 
    } else if (os instanceof FilterOutputStream) { 
     return recreateChainedOutputStream(os.out); 
    } 
} 

有沒有其他方法可以達到同樣的效果?

+0

看起來像是X-Y問題。爲什麼這需要? – Ferrybig

+1

我想編寫一個RolloverOutputStream,它可以自己滾動文件,其中消費者類應該能夠通過傳入基礎OutputStream(可以是FileOutputStream上的GZipOutputStream或普通的FileOutputStream或更多的組合)以及閾值應該在哪些文件上滾動。消費應用程序應該能夠無限期地繼續寫入,而RolloverOutputStream在數據大小超過閾值時處理翻轉。 – rajeshnair

+0

如果你想創建一個'RolloverOutputStream',創建'OutputStream'的自定義實現將會更容易,該實現有'setOutputStream()'方法來選擇它的目標。您當前的解決方案依賴於輸出流是鏈的頂端的事實,在所有應用中可能並非總是如此。 – Ferrybig

回答

1

您可以使用反射來訪問FilterOutputStream的os.out場,這可是有一些缺點:

  • 如果對方的OutputStream也是一種RolloverOutputStream的,你可以有一個很難重建它,
  • 如果其他的OutputStream具有自定義設置,如Gzip壓縮參數,你可以不可靠的閱讀
  • 如果有

一個快速和骯髒的實施recreateChainedOutputStream(可能是:

private final static Field out; 
{ 
    try { 
     out = FilterInputStream.class.getField("out"); 
     out.setAccessible(true); 
    } catch(Exception e) { 
     throw new RuntimeException(e); 
    } 
} 

public OutputStream recreateChainedOutputStream(OutputStream out) throws IOException { 
    if (out instanceof FilterOutputStream) { 
     Class<?> c = ou.getClass(); 
     COnstructor<?> con = c.getConstructor(OutputStream.class); 
     return con.invoke(this.out.get(out)); 
    } else { 
     // Other output streams... 
    } 
} 

雖然這可能是當前應用程序確定,這是一個很大的禁忌在生產世界,因爲大量不同種類的OutputStreams您的應用程序的可能會收到。

解決問題的更好方法是一種Function<String, OutputStream>,它可以作爲工廠爲指定文件創建OutputStream。通過這種方式,外部api可以控制OutputStream,而您的api可以處理多個文件名。這方面的一個例子是:

public class MyApi { 
    private final Function<String, OutputStream> fileProvider; 
    private OutputStream current; 
    public MyApi (Function<String, OutputStream> fileProvider, String defaultFile) { 
     this.fileProvider = fileProvider; 
     selectNewOutputFile(defaultFile); 
    } 
    public void selectNewOutputFile(String name) { 
     OutputStream current = this.current; 
     this.current = fileProvider.apply(name); 
     if(current != null) current.close(); 
    } 
} 

這然後可以在其它應用中被用作:

MyApi api = new MyApi(name->new FileOutputStream(name)); 

對於簡單FileOutputStream S,或可以用作:

MyApi api = new MyApi(name-> 
    new GZIPOutputStream(
     new CipherOutputStream(
      new CheckedOutputStream(
       new FileOutputStream(name), 
       new CRC32()), 
      chipper), 
     1024, 
     true) 
    ); 

對於文件流存儲校驗和使用new CRC32(),使用chipper切片,gzip根據具有同步寫入模式的1024緩衝區。

+0

使用lambda提升代碼片段的答案。雖然MyApi接受一個函數,但使用使它看起來像接受OutputStream參數。愛lambda表達的另一個原因! – rajeshnair

相關問題