Использование конвейерных потоков и jaxb

Я не могу понять, неправильно ли я использую конвейерные потоки или моя проблема связана с проблемой, описанной ниже.

У меня есть объект (называемый adi), который я маршалирую в файл, как показано ниже:

  final PipedInputStream pipedInputStream = new PipedInputStream();
  OutputStream pipedOutputStream = null;
  pipedOutputStream = new PipedOutputStream(pipedInputStream);
  log.info("marshalling away");
  final OutputStream outputStream = new FileOutputStream(new File(
          "target/test.xml"));
  m.marshal(adi, outputStream);
  outputStream.flush();
  outputStream.close();
  pipedOutputStream.write("test".getBytes());
  // m.marshal(adi, pipedOutputStream);
  pipedOutputStream.flush();
  pipedOutputStream.close();
  log.info("marshalling done");
  return pipedInputStream;
  • Этот код создает файл target/test.xml с ожидаемым содержимым (упорядоченный объект), проверяя, правильно ли работает упорядочивание в outputStream.
  • Код также генерирует pipedInputStream. Если я перебираю байты, извлеченные из этого потока, и печатаю их, он отображает «тест», подтверждая тот факт, что мой поток ввода/вывода правильно настроен и работает.

Тем не менее, когда я раскомментирую

  //m.marshal(adi, pipedOutputStream);  

код зависает навсегда (никогда не отображает «сортировка завершена»), в то время как я ожидаю, что код вернет входной поток, содержащий «тест», за которым следует мой упорядоченный объект.

Что мне не хватает?

Спасибо


person double07    schedule 01.12.2011    source источник


Ответы (1)


Я думаю, вы пытаетесь использовать его неправильно...

Из API (http://docs.oracle.com/javase/6/docs/api/java/io/PipedInputStream.html):

Обычно данные считываются из объекта PipedInputStream одним потоком, а данные записываются в соответствующий объект PipedOutputStream другим потоком. Попытка использовать оба объекта из одного потока не рекомендуется, так как это может привести к блокировке потока.

Что вы хотите сделать, так это:

  log.info("marshalling away");
  final OutputStream fileOutputStream = new FileOutputStream(new File(
          "target/test.xml"));
  m.marshal(adi, fileOutputStream);
  fileOutputStream.flush();
  fileOutputStream.close();
  final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
  outputStream.write("test".getBytes());
  m.marshal(adi, outputStream);
  outputStream.flush();
  final InputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
  outputStream.close();
  log.info("marshalling done");
  return inputStream;

Дополнительные примеры того, как превратить выходной поток во входной, см. здесь: http://ostermiller.org/convert_java_outputstream_inputstream.html

Существует способ, используя временный поток, что вы можете сделать что-то похожее на ваше исходное решение и конвейерные потоки.

person MattJenko    schedule 01.12.2011
comment
То, что вы говорите, имеет смысл. Итак, позвольте мне задать более общий вопрос: если мой контракт должен возвращать InputStream, который будет содержать мой упорядоченный объект, каким должен быть мой подход? Я застрял, упорядочив свой объект в StringWriter или FileWriter, а затем преобразовал полученную строку или файл в inputStream? Есть ли что-то более эффективное с точки зрения ресурсов? - person double07; 01.12.2011
comment
Извините, я обновил мой ответ, включив в него пример того, что делать, а также ссылку на другие возможности (тот, который похож на ваше исходное решение, но использует временный поток для выполнения части PipedOutputStream. - person MattJenko; 01.12.2011
comment
Спасибо, я сделал почти то же самое, что вы написали выше, за исключением того, что я прошел через FileInputStream и FileOutputStream, чтобы уменьшить требования к памяти. Вы уловили мою проблему в своем первом комментарии: я ожидал, что этот код будет выполняться в отдельном потоке (производя данные по мере их потребления) без настройки какой-либо многопоточной среды. Спасибо за помощь. - person double07; 01.12.2011
comment
Как я уже сказал, есть еще одна альтернатива: делать почти то же самое, что и вы, но выполнять часть «m.marshal(adi, outputStream)» внутри потока. См. последнюю ссылку, которую я предоставил, в разделе «Использование каналов». - person MattJenko; 01.12.2011