Как преобразовать OutputStream в InputStream?

Я нахожусь на стадии разработки, где у меня два модуля, и с одного я получил вывод как OutputStream и второй, который принимает только InputStream. Вы знаете, как преобразовать OutputStream в InputStream (а не наоборот, я имею в виду именно так), что я смогу подключить эти две части?

Спасибо

Ответ 1

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

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

Таким образом, можно подключить InputStream к OutputStream

InputStream----read---> intermediateBytes[n] ----write----> OutputStream

Как заметил кто-то, это способ copy() IOUtils позволяет вам это сделать. Не имеет смысла идти другим путем... надеюсь, это имеет смысл

UPDATE:

Конечно, чем больше я об этом думаю, тем больше я вижу, как это будет требовать. Я знаю, что некоторые из комментариев упоминаются в потоках ввода/вывода Piped, но есть и другая возможность.

Если отображаемый выходной поток является ByteArrayOutputStream, вы всегда можете получить полное содержимое, вызвав метод toByteArray(). Затем вы можете создать оболочку потока ввода с помощью подкласса ByteArrayInputStream. Эти два являются псевдопотоками, они оба в основном просто обертывают массив байтов. Таким образом, использование потоков таким образом технически возможно, но для меня это все еще очень странно...

Ответ 2

Похоже, что есть много ссылок и других подобных материалов, но нет реального кода, использующего каналы. Преимущество использования java.io.PipedInputStream и java.io.PipedOutputStream заключается в отсутствии дополнительного потребления памяти. ByteArrayOutputStream.toByteArray() возвращает копию исходного буфера, поэтому это означает, что все, что у вас есть в памяти, теперь имеет две копии. Затем запись в InputStream означает, что теперь у вас есть три копии данных.

Код:

// take the copy of the stream and re-write it to an InputStream
PipedInputStream in = new PipedInputStream();
final PipedOutputStream out = new PipedOutputStream(in);
new Thread(new Runnable() {
    public void run () {
        try {
            // write the original OutputStream to the PipedOutputStream
            originalByteArrayOutputStream.writeTo(out);
        } catch (IOException e) {
            // logging and exception handling should go here
        }
    }
}).start();

Этот код предполагает, что originalByteArrayOutputStream является ByteArrayOutputStream, поскольку он обычно является единственным используемым потоком вывода, если только вы не пишете файл. Надеюсь, это поможет! Самое замечательное в этом состоит в том, что, поскольку он находится в отдельном потоке, он также работает параллельно, поэтому все, что потребляет ваш поток ввода, также будет выводиться из вашего старого выходного потока. Это полезно, потому что буфер может оставаться меньше, и у вас будет меньше латентности и меньше использования памяти.

Ответ 3

Вам понадобится промежуточный класс, который будет задерживаться между ними. Каждый раз, когда вызывается InputStream.read(byte[]...), класс буферизации заполняет переданный в массиве байтов следующий фрагмент, переданный из OutputStream.write(byte[]...). Поскольку размеры блоков не могут быть одинаковыми, класс адаптера должен будет хранить определенную сумму до тех пор, пока он не будет достаточным для заполнения буфера чтения и/или сможет сохранить переполнение буфера.

В этой статье есть хорошая разбивка нескольких разных подходов к этой проблеме:

http://blog.ostermiller.org/convert-java-outputstream-inputstream

Ответ 5

Поскольку потоки ввода и вывода являются только начальной и конечной точкой, решение заключается в временном хранении данных в массиве байтов. Поэтому вы должны создать промежуточный ByteArrayOutputStream, из которого вы создаете byte[], который используется как вход для нового ByteArrayInputStream.

public void doTwoThingsWithStream(InputStream inStream, OutputStream outStream){ 
  //create temporary bayte array output stream
  ByteArrayOutputStream baos = new ByteArrayOutputStream();
  doFirstThing(inStream, baos);
  //create input stream from baos
  InputStream isFromFirstData = new ByteArrayInputStream(baos.toByteArray()); 
  doSecondThing(isFromFirstData, outStream);
}

Надеюсь, что это поможет.

Ответ 6

Я столкнулся с той же проблемой при преобразовании a ByteArrayOutputStream в ByteArrayInputStream и решил ее с помощью производного класса из ByteArrayOutputStream, который может вернуть ByteArrayInputStream, который инициализируется внутренним буфером ByteArrayOutputStream. Таким образом, не используется дополнительная память, и "преобразование" выполняется очень быстро:

package info.whitebyte.utils;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;

/**
 * This class extends the ByteArrayOutputStream by 
 * providing a method that returns a new ByteArrayInputStream
 * which uses the internal byte array buffer. This buffer
 * is not copied, so no additional memory is used. After
 * creating the ByteArrayInputStream the instance of the
 * ByteArrayInOutStream can not be used anymore.
 * <p>
 * The ByteArrayInputStream can be retrieved using <code>getInputStream()</code>.
 * @author Nick Russler
 */
public class ByteArrayInOutStream extends ByteArrayOutputStream {
    /**
     * Creates a new ByteArrayInOutStream. The buffer capacity is
     * initially 32 bytes, though its size increases if necessary.
     */
    public ByteArrayInOutStream() {
        super();
    }

    /**
     * Creates a new ByteArrayInOutStream, with a buffer capacity of
     * the specified size, in bytes.
     *
     * @param   size   the initial size.
     * @exception  IllegalArgumentException if size is negative.
     */
    public ByteArrayInOutStream(int size) {
        super(size);
    }

    /**
     * Creates a new ByteArrayInputStream that uses the internal byte array buffer 
     * of this ByteArrayInOutStream instance as its buffer array. The initial value 
     * of pos is set to zero and the initial value of count is the number of bytes 
     * that can be read from the byte array. The buffer array is not copied. This 
     * instance of ByteArrayInOutStream can not be used anymore after calling this
     * method.
     * @return the ByteArrayInputStream instance
     */
    public ByteArrayInputStream getInputStream() {
        // create new ByteArrayInputStream that respects the current count
        ByteArrayInputStream in = new ByteArrayInputStream(this.buf, 0, this.count);

        // set the buffer of the ByteArrayOutputStream 
        // to null so it can't be altered anymore
        this.buf = null;

        return in;
    }
}

Я помещал материал в github: https://github.com/nickrussler/ByteArrayInOutStream

Ответ 7

ByteArrayOutputStream buffer = (ByteArrayOutputStream) aOutputStream;
byte[] bytes = buffer.toByteArray();
InputStream inputStream = new ByteArrayInputStream(bytes);

Ответ 8

Если вы хотите создать OutputStream из InputStream, есть одна основная проблема. Метод, записывающий в блок OutputStream до тех пор, пока он не будет выполнен. Таким образом, результат доступен, когда метод записи завершен. Это имеет 2 последствия:

  • Если вы используете только один поток, вам нужно подождать, пока все не будет записано (поэтому вам нужно сохранить данные потока в памяти или на диске).
  • Если вы хотите получить доступ к данным до их завершения, вам понадобится второй поток.

Вариант 1 может быть реализован с использованием массивов байтов или поданных. Вариант 1 может быть реализован с использованием pipies (либо напрямую, либо с дополнительной абстракцией - например, RingBuffer или google lib из другого комментария).

В действительности со стандартным java нет другого способа решить проблему. Каждое решение является реализацией одного из них.

Существует одна концепция под названием "продолжение" (подробности см. wikipedia). В этом случае в основном это означает:

  • существует специальный выходной поток, который ожидает определенный объем данных
  • если достигнуто количество, поток передает управление ему, что является специальным входным потоком.
  • входной поток делает доступным объем данных до его считывания, после чего он передает управление в выходной поток

В то время как на некоторых языках встроена эта концепция, для java вам требуется некоторая "магия". Например, "commons-javaflow" из apache реализует такие для java. Недостатком является то, что это требует некоторых специальных модификаций байт-кода во время сборки. Поэтому было бы целесообразно поместить все материалы в дополнительную библиотеку с помощью скриптов пользовательской сборки.

Ответ 9

Хотя вы не можете преобразовать OutputStream в InputStream, java предоставляет способ использования PipedOutputStream и PipedInputStream, чтобы вы могли иметь данные, записанные в PipedOutputStream, чтобы стать доступными через связанный PipedInputStream.
Некоторое время назад я столкнулся с аналогичной ситуацией при работе с сторонними библиотеками, которым требуется экземпляр InputStream для передачи им вместо экземпляра OutputStream.
Как я исправил эту проблему, это использовать PipedInputStream и PipedOutputStream,
Кстати, они сложны в использовании, и вы должны использовать многопоточность для достижения того, чего хотите. Недавно я опубликовал реализацию на github, которую вы можете использовать.
Вот ссылка . Вы можете пройти через wiki, чтобы понять, как его использовать.

Ответ 10

Старый пост, но может помочь другим, Используйте этот способ:

OutputStream out = new ByteArrayOutputStream();
...
out.write();
...
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(out.toString().getBytes()));

Ответ 11

Я думаю, что лучший способ подключить InputStream к OutputStream через потоки с каналами - доступен в пакете java.io, как показано ниже:

// 1- Define stream buffer
private static final int PIPE_BUFFER = 2048;

// 2 -Create PipedInputStream with the buffer
public PipedInputStream inPipe = new PipedInputStream(PIPE_BUFFER);

// 3 -Create PipedOutputStream and bound it to the PipedInputStream object
public PipedOutputStream outPipe = new PipedOutputStream(inPipe);

// 4- PipedOutputStream is an OutputStream, So you can write data to it
// in any way suitable to your data. for example:
while (Condition) {
     outPipe.write(mByte);
}

/*Congratulations:D. Step 4 will write data to the PipedOutputStream
which is bound to the PipedInputStream so after filling the buffer
this data is available in the inPipe Object. Start reading it to
clear the buffer to be filled again by the PipedInputStream object.*/

По моему мнению, для этого кода есть два основных преимущества:

1 - Дополнительный расход памяти отсутствует, кроме буфера.

2 - Вам не нужно вручную обрабатывать очереди данных