2016-01-13 13 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

相关问题