Come si fa a unire due flussi di ingresso in Java?
-
09-09-2019 - |
Domanda
Avendo due InputStreams in Java, c'è un modo per unirle così si finisce con un InputStream che ti dà l'uscita di entrambi i flussi? Come?
Soluzione
Come commentato, non è chiaro cosa si intende per unione.
Prendendo a disposizione di ingresso "a caso" da entrambi è complicata dal InputStream.available
non necessariamente ti dà una risposta utile e bloccando il comportamento dei flussi. Si avrebbe bisogno di due fili di leggere dai ruscelli e poi passando di nuovo i dati attraverso, per esempio, java.io.Piped(In|Out)putStream
(anche se quelle classi hanno problemi). In alternativa, per alcuni tipi di flusso può essere possibile utilizzare una diversa interfaccia, ad esempio java.nio
canali non bloccanti.
Se si desidera che l'intero contenuto del primo flusso di input seguito dal secondo:. new java.io.SequenceInputStream(s1, s2)
Altri suggerimenti
java.io.SequenceInputStream
potrebbe essere quello che ti serve. Esso accetta un'enumerazione di flussi, e stamperà il contenuto del primo flusso, poi la seconda, e così via fino a che tutti i flussi sono vuoti.
È possibile scrivere un'implementazione InputStream
personalizzato che fa questo. Esempio:
import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
import java.util.Deque;
import java.util.LinkedList;
public class CatInputStream extends InputStream {
private final Deque<InputStream> streams;
public CatInputStream(InputStream... streams) {
this.streams = new LinkedList<InputStream>();
Collections.addAll(this.streams, streams);
}
private void nextStream() throws IOException {
streams.removeFirst().close();
}
@Override
public int read() throws IOException {
int result = -1;
while (!streams.isEmpty()
&& (result = streams.getFirst().read()) == -1) {
nextStream();
}
return result;
}
@Override
public int read(byte b[], int off, int len) throws IOException {
int result = -1;
while (!streams.isEmpty()
&& (result = streams.getFirst().read(b, off, len)) == -1) {
nextStream();
}
return result;
}
@Override
public long skip(long n) throws IOException {
long skipped = 0L;
while (skipped < n && !streams.isEmpty()) {
int thisSkip = streams.getFirst().skip(n - skipped);
if (thisSkip > 0)
skipped += thisSkip;
else
nextStream();
}
return skipped;
}
@Override
public int available() throws IOException {
return streams.isEmpty() ? 0 : streams.getFirst().available();
}
@Override
public void close() throws IOException {
while (!streams.isEmpty())
nextStream();
}
}
Questo codice non è testato, così il vostro chilometraggio può variare.
Non è che mi viene in mente. Probabilmente si dovrà leggere il contenuto dei due flusso in un byte [] e quindi creare un ByteArrayInputStream da questo.
Ecco un'implementazione MVAR specifico array di byte (assicuratevi di aggiungere la tua definizione del pacchetto). Da qui, è banale scrivere un flusso di input sui flussi unite. Posso inviare anche questo, se richiesto.
import java.nio.ByteBuffer;
public final class MVar {
private static enum State {
EMPTY, ONE, MANY
}
private final Object lock;
private State state;
private byte b;
private ByteBuffer bytes;
private int length;
public MVar() {
lock = new Object();
state = State.EMPTY;
}
public final void put(byte b) {
synchronized (lock) {
while (state != State.EMPTY) {
try {
lock.wait();
} catch (InterruptedException e) {}
}
this.b = b;
state = State.ONE;
lock.notifyAll();
}
}
public final void put(byte[] bytes, int offset, int length) {
if (length == 0) {
return;
}
synchronized (lock) {
while (state != State.EMPTY) {
try {
lock.wait();
} catch (InterruptedException e) {}
}
this.bytes = ByteBuffer.allocateDirect(length);
this.bytes.put(bytes, offset, length);
this.bytes.position(0);
this.length = length;
state = State.MANY;
lock.notifyAll();
}
}
public final byte take() {
synchronized (lock) {
while (state == State.EMPTY) {
try {
lock.wait();
} catch (InterruptedException e) {}
}
switch (state) {
case ONE: {
state = State.EMPTY;
byte b = this.b;
lock.notifyAll();
return b;
}
case MANY: {
byte b = bytes.get();
state = --length <= 0 ? State.EMPTY : State.MANY;
lock.notifyAll();
return b;
}
default:
throw new AssertionError();
}
}
}
public final int take(byte[] bytes, int offset, int length) {
if (length == 0) {
return 0;
}
synchronized (lock) {
while (state == State.EMPTY) {
try {
lock.wait();
} catch (InterruptedException e) {}
}
switch (state) {
case ONE:
bytes[offset] = b;
state = State.EMPTY;
lock.notifyAll();
return 1;
case MANY:
if (this.length > length) {
this.bytes.get(bytes, offset, length);
this.length = this.length - length;
synchronized (lock) {
lock.notifyAll();
}
return length;
}
this.bytes.get(bytes, offset, this.length);
this.bytes = null;
state = State.EMPTY;
length = this.length;
lock.notifyAll();
return length;
default:
throw new AssertionError();
}
}
}
}