W Javie muszę umieścić zawartość z OutputStream (I wypełnić dane do tego strumienia samodzielnie) do ByteBuffer. Jak to zrobić w prosty sposób?Jak umieścić dane z OutputStream w ByteBuffer?
Odpowiedz
Można utworzyć ByteArrayOutputStream
i napisać do niego i wyodrębnić zawartość jako byte[]
przy użyciu toByteArray()
. Następnie ByteBuffer.wrap(byte [])
utworzy ByteBuffer
z zawartością wyjściowej tablicy bajtów.
To jest dokładnie to, co zrobiłem tuż przed przeczytaniem twojego komentarza. Mogę więc zatwierdzić, że to działa :)) – drasto
Niestety, 'ByteArrayOutputStream # toByteArray()' tworzy kopię podstawowej tablicy bajtów, więc podczas gdy ta recepta jest prosta, nie jest tak efektywna, jak byśmy chcieli. Jednakże, ponieważ 'ByteBuffer' ma ustaloną pojemność, chęć zapisania dowolnej ilości danych przez' OutputStream' do 'ByteBuffer' jest nie do pogodzenia. – seh
@seh To nie musi tak być - zobacz moją odpowiedź. – mark
Spróbuj użyć PipedOutputStream zamiast OutputStream. Następnie można podłączyć PipedInputStream, aby odczytać dane z powrotem z PipedOutputStream.
Wygląda dobrze. Podobne myślenie można wykonać za pomocą metody ByteArrayOutputStream, wywołując jej metodę newInputStream. Istnieje jednak szersze rozwiązanie - do owijania tablicy, która tworzy kopię zapasową ByteArrayOutputStream bezpośrednio w ByteBuffer. Właśnie to zrobiłem. – drasto
Istnieje skuteczniejszy wariant odpowiedzi @ DJClayworth.
Jak @seh prawidłowo zauważył, ByteArrayOutputStream.toByteArray()
zwraca kopię obiektu podkład byte[]
, które mogą być nieskuteczne. Jednak obiekt bazowy oraz obiekt z bajtami są chronionymi elementami klasy ByteArrayOutputStream
. Stąd też można stworzyć swój własny wariant ByteArrayOutputStream wystawiając je bezpośrednio:
public class MyByteArrayOutputStream extends ByteArrayOutputStream {
public MyByteArrayOutputStream() {
}
public MyByteArrayOutputStream(int size) {
super(size);
}
public int getCount() {
return count;
}
public byte[] getBuf() {
return buf;
}
}
Korzystanie z tej klasy jest proste:
MyByteArrayOutputStream out = new MyByteArrayOutputStream();
fillTheOutputStream(out);
return new ByteArrayInputStream(out.getBuf(), 0, out.getCount());
W rezultacie, gdy cała moc jest napisany ten sam bufor służy jako podstawa strumienia wejściowego.
Dobry punkt, @mark. Mam takie klasy w kilku moich projektów Java, zwykle ograniczone jako pakiet-prywatne klasy o nazwie "PromiscuousByteArrayOutputStream". Nazwa jest celowo długa i złowieszcza. – seh
getCount() nie jest potrzebny, ponieważ ByteArrayOutputStream.size() zwraca liczbę. –
Chociaż powyższe odpowiedzi rozwiązują problem, żaden z nich nie jest wydajny, jak można oczekiwać od NIO. ByteArrayOutputStream lub MyByteArrayOutputStream najpierw zapisują dane w pamięci sterty Java, a następnie kopiują ją do ByteBuffer, co znacznie wpływa na wydajność.
Skuteczną implementacją byłoby samodzielne pisanie klasy ByteBufferOutputStream. Właściwie to dość łatwe do zrobienia. Musisz po prostu podać metodę write(). Zobacz ten link dla ByteBufferInputStream.
ponieważ możemy potrzebować ponownego użycia istniejącego ByteBuffer (i jego podstawowej tablicy) dla OutputStream zamiast przydzielania nowej tablicy, aby uzyskać nowy ByteBuffer, uważam, że ta odpowiedź jest bardziej akceptowalna. – Ambling
Ogólnie nie można odczytać bezpośrednio ze strumienia wyjściowego. Jeśli sam je wypełnisz, dlaczego nie możesz go również wypełnić w ByteBuffer? –
Możliwe jest odczytanie z niego pośrednio i bezpośrednio, jeśli utworzysz klasę dziedziczącą formę OutputStream i umożliwiającą odczytanie jej bezpośrednio. Nie wypełniłem danych osobiście, niektóre ramy (i kod frameworka nie chcę dotykać przyczyny). Zobacz także mój inny komentarz i odpowiedzi. – drasto