2016-01-13 11 views
0

У меня есть OutputStream, который можно инициализировать как цепочку OutputStreams. Там может быть любой уровень цепочки. Единственное, что гарантировано, это то, что в конце цепочки есть FileOutputStream.Как я могу восстановить цепочку OutputStream с измененным только именем файла

Мне нужно воссоздать этот цепной выходной поток с измененным именем файла в FileOutputStream. Это было бы возможно, если бы была доступна переменная out (которая хранит базовый последовательный выходной поток); как показано ниже.

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 (который может быть GZipOutputStream через FileoutStream или простой FileOutputStream или еще какая-то комбинация этого) вместе с порогом при котором файлы должны быть перевернуты. Потребляющее приложение должно иметь возможность продолжать писать неограниченное время, в то время как RolloverOutputStream обрабатывает опрокидывание, когда размер данных пересекает порог. – rajeshnair

+0

Если вы хотите создать «RolloverOutputStream», было бы проще создать пользовательскую реализацию 'OutputStream', которая имеет метод' setOutputStream() 'для выбора своей цели. Ваше текущее решение основывается на том, что выходной поток является вершиной цепочки, что не всегда верно для всех приложений. – Ferrybig

ответ

1

Вы можете использовать отражение для доступа к os.out поле FilterOutputStream, это, однако, имеет некоторые недостатки:

  • Если другой 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 s для названного файла. Таким образом, внешний api сохраняет свой контроль над OutputStream s, в то время как ваш 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 с, или использоваться в качестве:

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

For A файловый поток, который хранится с контрольной суммой с использованием new CRC32(), скопирован с использованием chipper, gzip в соответствии с 1024 буфером с режимом записи в режиме синхронизации.

+0

Продвижение ответа на фрагмент кода с использованием лямбда. Хотя MyApi принимает функцию, но использование делает ее похожей на прием параметра OutputStream. Еще одна причина любить выражение лямбды! – rajeshnair