Newsgroup: it.comp.java
Titolo: Usare sia ObjectOutputStream che BufferedOutputStream nello stesso codice

Ciao a tutti,
vi chiedo scusa in anticipo se quello che sto per chiedervi dovesse 
risultare un po' confuso e rivelare tutta la mia ignoranza 
sull'argomento ma purtroppo ï¿œ la prima volta che mi trovo a lavorare con 
questo tipo di operazioni e quindi sono parecchio inesperto.
In pratica volevo sapere se un mio dubbio corrisponde a realtï¿œ e cioï¿œ: 
mi confermate che non ï¿œ possibile usare sia ObjectOutputStream che 
BufferedOutputStream nello stesso codice in questo modo?
private ObjectOutputStream oos = new 
ObjectOutputStream(s.getOutputStream());
private BufferedOutputStream bos = new 
BufferedOutputStream(s.getOutputStream());
// invio di alcuni oggetti serializzati su oos con
// i vari metodi oos.writeObject()
// ...
// invio del contenuto di un file su bos con il
// metodo bos.write()
Purtroppo sono costretto a usare questo metodo per un problema che ora 
vi spiego. Ho necessitï¿œ di inviare alcuni oggetti serializzati tra 
server e client. Poi perï¿œ, a un certo punto della mia applicazione, 
serve che io sulla stessa socket mandi il contenuto di un file byte dopo 
byte. Ovviamente inviare questi byte come oggetti serializzati su una 
ObjectOutputStream non funziona quindi ho pensato di utilizzare una 
BufferedOutputStream per fare ciï¿œ.
Il problema ï¿œ che questo ï¿œ quello che mi capita:
inizialmente invio svariati oggetti serializzati su OOS --> OK
poi invio del primo file su BOS --> OK
a questo punto provo nuovamente a inviare oggetti su OOS --> ERRORE
In particolare l'errore che mi dï¿œ ï¿œ: java.io.StreamCorruptedException: 
invalid type code: 64
Io sinceramente non so come cavarci piede e potete immaginare che non 
sia facile trovare informazioni su Google riguardo questo tipo di problemi.
In pratica perï¿œ la mia domanda ï¿œ questa: come faccio se voglio inviare 
sulla stessa socket degli oggetti serializzati ma anche dei bytes 
contenuti in un file? La prima soluzione a cui avevo pensato era di 
serializzare anche i bytes che mandavo ma purtroppo non sono riuscito a 
realizzarla. Ora sto pensando: ï¿œ possibile variare il tipo di 
OutputStream "in corsa" in modo che quando mi fa comodo mando oggetti 
serializzati su una ObjectOutputStream e quando voglio invece mando 
bytes su una BufferedOutputStream?
Grazie mille per la disponibilitï¿œ
-- 
Elminster

 BufferedOutputStream per fare ciï¿œ.
Ho dato solo uno sguardo veloce, ma la butto lï¿œ: hai pensato ad usare 
ByteArrayInputStream? Il file letto andrebbe in un array di byte, che 
potrebbe essere contenuto in una classe apposita, da inviare 
serializzata (o qualcosa del genere). Ovvero (server) legge file in un 
array - invia l'array serializzato - (client) legge l'array serializzato 
- capisce da qualche dato inviato insieme all'array che si tratta di un 
file - ci fa quello che gli serve.

a questo punto provo nuovamente a inviare oggetti su OOS --> ERRORE
Perchï¿œ l'uso di BufferedOutputStream precedente non ha concluso lo
svuotamento in uscita del buffer, e quindi incominci a trasmettere di
nuovo _direttamente_ sul socket senza sapere cosa si aspetta l'altro
lato della connessione. Risultato: flusso corrotto.
Per tirare le somme, i miei suggerimenti sono:
1) Costruisci prima il BufferedOutputStream, e sopra di esso
ObjectOutputStream
2) PRIMA di trasmettere il file, magari manda (sempre tramite
ObjectOutputStream) un Integer o un Long contenente il conteggio dei
byte che compongono il file
2a) Quando leggerai il file tieni conto della dimensione ricevuta. Hai
diversi metodi:
- conta i byte ricevuti uno per uno, e confronta il conteggio con la
dimensione ricevuta in all'inizio
- oppure: alloca un buffer (array di byte) corrispondente alla
dimensione del file, e leggilo tramite un'unica chiamata a
InputStream.read(buffer,0,buffer.length). Questa chiamata non termina
fino a quando il file non ï¿œ stato letto per intero (oppure se il socket
viene chiuso in anticipo). Controlla il valore restituito da read per
sapere se l'hai ricevuto tutto.
3) DOPO aver usato direttamente BufferedOutputStream per trasmettere il
file, assicurati di svuotare il buffer in uscita (bos.flush())
4) Ricomincia a mandare oggetti su ObjectOutputStream.
5) Concluso il lavoro, chiama sempre bos.flush prima di bos.close.
Spero di non aver infilato qualche cantonata.
Hope that helps!
-- 
Scientology: se la conosci la eviti, se la conosci non ti uccide...
http://xenu.com-it.net
 - 
http://xenu.freewinds.cx
 - 
http://www.xenu.net
(per rispondere personalmente leva IlDitoDalCulo)
---> 09 F9 11 02 9D 74 E3 5B D8 41 56 C5 63 56 88 C0 <---

 trasmissione del buffer)
In effetti hai ragione, molto probabilmente (quasi di sicuro) il 
problema ï¿œ che non avevo svuotato completamente il buffer prima di 
inviare nuovamente altre cose.
Comunque ho abbandonato questa via perchï¿œ, come mi ha suggerito Marco, 
ho preferito inviare il file come buffer di byte all'interno di un'altra 
classe serializzata. In questo modo prendo due piccioni con una fava: 
oltre al file invio anche delle altre informazioni (metadati) sul file 
che avrei comunque dovuto inviare e poi ne guadagna la pulizia del 
codice. In questo modo infatti creo una classe FileMsg che all'interno 
contiene i bytes del file oltre ad alcune informazioni aggiuntive come 
il nome del file, la sua data di ultima modifica, le sue dimensioni. ecc.
A questo punto perï¿œ approfitto della vostra gentilezza per chiedervi 
delle spiegazioni su un'ulteriore problema che ï¿œ sorto proprio oggi 
nell'inviare un file. Apro un alto thread per dare maggiore visibilitï¿œ 
alla mia richiesta. :) Se potete aiutatemi anche lï¿œ!
-- 
Elminster