View Full Version : [JAVA] problemino con ByteArrayOutputStream
redcloud
05-12-2007, 18:24
Salve, devo inviare su un socket una Stringa convertita in array di byte. Per convertire la stringa uso
byte[] buffer = "pippoplutopaperinopaperogaeziopaperone".getBytes();
dopodichè devo inviare questo buffer su un OutputStream di un socket. Non lo devo inviare tutto subito, ma 10 byte la volta. Mi hanno consigliato di usare ByteArrayOutputStream ma non ho capito come... mi date una mano?
byte[] buffer = "pippoplutopaperinopaperogaeziopaperone".getBytes();
Sì, tecnicamente corretto. Però vorrei precisare una cosa. Quando si parla di conversione da String a sequenza di byte (o viceversa) è necessario tenere sempre in considerazione il "charset" usato per codificare la sequenza di byte.
Ora ... getBytes() fornisce una sequenza di byte codificata secondo il charset di "default" della piattaforma (quale sia, dipende....). Visto che devi inviare la sequenza su socket, immagino ad un altro host, c'è da prestare attenzione ad una cosa: chi riceve la sequenza sa esattamente quale charset è stato usato per la codifica??
dopodichè devo inviare questo buffer su un OutputStream di un socket. Non lo devo inviare tutto subito, ma 10 byte la volta. Mi hanno consigliato di usare ByteArrayOutputStream ma non ho capito come... mi date una mano?No, semmai è proprio la classe diametralmente opposta, cioè ByteArrayInputStream. Un ByteArrayInputStream lo si costruisce passando un array di byte e poi tramite i metodi read() si può leggere un tot di byte per volta (nel tuo caso, come hai detto, 10), che poi scriverai sul socket.
redcloud
05-12-2007, 19:42
Sì, tecnicamente corretto. Però vorrei precisare una cosa. Quando si parla di conversione da String a sequenza di byte (o viceversa) è necessario tenere sempre in considerazione il "charset" usato per codificare la sequenza di byte.
Ora ... getBytes() fornisce una sequenza di byte codificata secondo il charset di "default" della piattaforma (quale sia, dipende....). Visto che devi inviare la sequenza su socket, immagino ad un altro host, c'è da prestare attenzione ad una cosa: chi riceve la sequenza sa esattamente quale charset è stato usato per la codifica??
Si ho tralasciato il discorso del charset perchè chi riceverà saprà come interpretare i byte.
No, semmai è proprio la classe diametralmente opposta, cioè ByteArrayInputStream. Un ByteArrayInputStream lo si costruisce passando un array di byte e poi tramite i metodi read() si può leggere un tot di byte per volta (nel tuo caso, come hai detto, 10), che poi scriverai sul socket.
Ah e come li scrivo sul socket? Mi fai un esempio spiccio? Ti ringrazio molto.
Ah e come li scrivo sul socket? Mi fai un esempio spiccio? Ti ringrazio molto.Semplificando e ignorando, per brevità, eccezioni ecc....:
ByteArrayInputStream bais = new ByteArrayInputStream (arrBytes);
byte[] buf = new byte[10];
int len;
while ((len = bais.read (buf)) > 0)
os.write (buf, 0, len);
Per 'os' intendo in generale un OutputStream associato al socket ... poi non so esattamente cosa userai.
redcloud
05-12-2007, 20:18
Semplificando e ignorando, per brevità, eccezioni ecc....:
ByteArrayInputStream bais = new ByteArrayInputStream (arrBytes);
byte[] buf = new byte[10];
int len;
while ((len = bais.read (buf)) > 0)
os.write (buf, 0, len);
Per 'os' intendo in generale un OutputStream associato al socket ... poi non so esattamente cosa userai.
arrBytes è il byte[] che mi da getBytes()?
Quindi in pratica sto cavolo di bytearray è come se fosse un array con iteratore annesso: una figata! Ma esiste anche per altri tipi diversi da byte, chessò, StringArray, IntegerArray, o non ha senso?
Quindi fin quando read riesce a riempire il buf, len sarà sempre uguale alla lunghezza di buf (cioè 10)?
Grazie parecchio!
redcloud
05-12-2007, 20:19
Un'altra cosa. Se lo stream collegato al socket è di tipo DataOutputStream va bene lo stesso?
arrBytes è il byte[] che mi da getBytes()?Esatto.
Quindi in pratica sto cavolo di bytearray è come se fosse un array con iteratore annesso: una figata! Ma esiste anche per altri tipi diversi da byte, chessò, StringArray, IntegerArray, o non ha senso?Ci sono CharArrayReader/CharArrayWriter che fanno una cosa concettualmente uguale.
Nel package java.nio ci sono classi per gestire dei Buffer più particolari (e differenti dagli stream), che si usano tipicamente con i "channel".
Quindi fin quando read riesce a riempire il buf, len sarà sempre uguale alla lunghezza di buf (cioè 10)?Salvo l'ultimo blocco che potrebbe essere < 10. Quando non ci sono più byte, la read() ritorna -1, quindi il ciclo termina, per come ho posto la condizione.
Grazie parecchio!Please.
Un'altra cosa. Se lo stream collegato al socket è di tipo DataOutputStream va bene lo stesso?Si va benissimo perché è-un OutputStream. Io infatti non potevo sapere se usavi un DataOutputStream o un ObjectOutputStream!
redcloud
05-12-2007, 20:55
Si va benissimo perché è-un OutputStream. Io infatti non potevo sapere se usavi un DataOutputStream o un ObjectOutputStream!
Grazie. I casini me li ha creati un po' l'ereditarietà tra ArrayByteOutputStream, DataOutputStream e OutputStream. I primi infatti estendono OutputStream ma sono proprio due cose diverse tra loro e non riuscivo a capire come poter trasformare un ArrayByteOutputStream in uno stream direttamente collegabile a uno stream preso da socket. In questi casi come si fa? Si deve solo leggere attentamente la documentazione?
Grazie. I casini me li ha creati un po' l'ereditarietà tra ArrayByteOutputStream, DataOutputStream e OutputStream. I primi infatti estendono OutputStream ma sono proprio due cose diverse tra loro e non riuscivo a capire come poter trasformare un ArrayByteOutputStream in uno stream direttamente collegabile a uno stream preso da socket. In questi casi come si fa? Si deve solo leggere attentamente la documentazione?Le varie classi che hai detto sono semplicemente a livelli di "astrazione" differenti. OutputStream è una classe astratta ed è la "base" di tutte le altre. DataOutputStream/ObjectOutputStream se vai a vedere nella documentazione, possono essere create passando appunto un OutputStream (che in genere è di livello più "basso" come un FileOutputStream o quello di un socket).
Ma nel tuo caso non serviva certo ArrayByteOutputStream, perché non devi creare l'array ma, avendolo già, leggerlo a pezzetti. Tra l'altro, volendo essere pignoli, si potrebbe fare anche senza usare ByteArrayInputStream. Avendo l'array di byte, ti bastava scrivere i blocchi di 10 byte ragionando sugli offset: da offset 0 len 10, da offset 10 len 10, ecc....
redcloud
05-12-2007, 21:12
Ma nel tuo caso non serviva certo ArrayByteOutputStream, perché non devi creare l'array ma, avendolo già, leggerlo a pezzetti. Tra l'altro, volendo essere pignoli, si potrebbe fare anche senza usare ByteArrayInputStream. Avendo l'array di byte, ti bastava scrivere i blocchi di 10 byte ragionando sugli offset: da offset 0 len 10, da offset 10 len 10, ecc....
Lo so, era proprio per evitare il lavoraccio che forse mi hanno consigliato di usare quella classe, visto che è lei che si occupa di leggere tot byte volta per volta senza preoccuparsi degli offset, visto che anche tu in 2 righe hai risolto il problema...
Grazie.
visto che anche tu in 2 righe hai risolto il problema...Sì, in effetti con ByteArrayInputStream la soluzione è lineare e "pulita", anche se c'è chiaramente un leggero overhead (la creazione del ByteArrayInputStream, la creazione del buf, la lettura con copia nel buf).
Volendolo fare senza ByteArrayInputStream comunque non è proprio un lavoraccio:
byte[] dati = ......
int off = 0;
int len = 10;
while (off < dati.length)
{
len = Math.min (dati.length - off, len);
os.write (dati, off, len);
off += len;
}
redcloud
06-12-2007, 16:05
Scusami, una cosa ancora...
mi capita che l'ultimo ciclo di lettura legga meno caratteri della dimensione del buffer e quindi ottengo un buffer con dati sporchi nella parte finale. Come posso ottenere l'ultimo buffer di dimensione effettiva dei byte rimanenti? (scusa l'ingarbugliamento)
mi capita che l'ultimo ciclo di lettura legga meno caratteri della dimensione del buffer e quindi ottengo un buffer con dati sporchi nella parte finale. Come posso ottenere l'ultimo buffer di dimensione effettiva dei byte rimanenti? (scusa l'ingarbugliamento)Stai usando la soluzione con ByteArrayInputStream?? L'esempio di codice che ho postato all'inizio mi sembra(va) chiaro: quando leggo con la read(), devo tenere in considerazione il suo valore di ritorno (il numero di byte letti) perché lo devo usare nella write. Se l'ultimo blocco è lungo 6 e non 10, entrerò ancora nel ciclo (essendo > 0) e la write la farò di 6 byte.
redcloud
06-12-2007, 18:56
Hai ragione, sbagliavo io a usare l'offset. Grazie!
Ho un altro quesito da porti:
InputStream in = socket.getInputStream();
while(in.read() >= 0)
System.out.println("DENTRO");
System.out.println("FUORI");
Perchè una volta inviati tutti i dati sul socket, FUORI non viene mai stampato? La read mi sembra di aver capito che è bloccante ma quando ritorna -1? Io scrivo sul socket semplicemente un byte[]...
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.