Обертывание PipedInputStream с BufferedInputStream - PullRequest
4 голосов
/ 10 февраля 2011

У меня есть OutputStream, из которого мне нужно было прочитать, поэтому я использовал следующий (Groovy) код для получения ссылки InputStream на данные:

PipedInputStream inputStream = new PipedInputStream()
    PipedOutputStream outputStream = new PipedOutputStream(inputStream)
    new Thread(
            new Runnable() {
                public void run() {
                    // Some API method
                    putDataInOutputStream(outputStream)
                    outputStream.close()
                }
            }
    ).start()

handler.process(inputStream)

В этом случае обработчик - это некоторый класс, который реализует интерфейс, который имеет этот метод:

public void process(InputStream stream);

Проблема, которая возникла в наших новых требованиях, заключалась в том, что в потоке была некоторая предварительная обработка, и поэтому мне нужно прочитать поток как минимум дважды в методе handler.process (). Вот пример кода из одной реализации:

public void process(InputStream stream) {
    def bufferedStream = new BufferedInputStream(stream, 30 * 1048576)  // 30 MB
    bufferedStream.mark(Integer.MAX_VALUE)
    parseMetadata(bufferedStream)
    bufferedStream.reset()
    doTheThingYouDo(bufferedStream)
 }

Я знаю, что для некоторых входных данных я не достигаю предела 30 МБ или размера буфера Integer.MAX_VALUE . Однако я всегда получаю следующее исключение:

java.io.IOException: Stream closed

Это вообще возможно? Я думаю, что проблема заключается в закрытии потока в PipedOutputStream, но я не знаю, как это предотвратить или, возможно, я создаю больше проблем, будучи новичком в Java Stream IO.

1 Ответ

2 голосов
/ 10 февраля 2011

Мое лучшее предположение, что ваш parseMetadata каким-то образом закрыл поток.Я попробовал ваш сценарий, и он отлично работает для меня.В общем, закрытие OutputStream до того, как обработчик завершит чтение, это не проблема, это именно то, для чего нужны потоковые потоки.

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

ByteArrayOutputStream out = new ByteArrayOutputStream();

fillTheOutput(out);

ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());

pass1(in);
in.reset();
pass2(in);

Если вы не возражаете, чтобы все было в памяти, у вас все равно проблемы, так как ваш BufferedInputStream примерното же самое.

edit : обратите внимание, что вы можете легко создать новый ByteArrayInputStream на основе байтового массива, чего нельзя делать с обычными потоками.

...