Perché & # 8220; piping & # 8221; un blocco CharBuffer?
Domanda
Perché si blocca il seguente metodo?
public void pipe(Reader in, Writer out) { CharBuffer buf = CharBuffer.allocate(DEFAULT_BUFFER_SIZE); while( in.read(buf) >= 0 ) { out.append(buf.flip()); } }
Soluzione
Rispondere alla mia domanda: devi chiamare buf.clear ()
tra read
s. Presumibilmente, read
è sospeso perché il buffer è pieno. Il codice corretto è
public void pipe(Reader in, Writer out) { CharBuffer buf = CharBuffer.allocate(DEFAULT_BUFFER_SIZE); while( in.read(buf) >= 0 ) { out.append(buf.flip()); buf.clear(); } }
Altri suggerimenti
Suppongo che sia un deadlock. In.read (buf) blocca CharBuffer e impedisce la chiamata out.append (buf).
Ciò presuppone che CharBuffer utilizzi blocchi (di qualche tipo) nell'implementazione. Cosa dice l'API sulla classe CharBuffer?
Modifica: scusa, una specie di corto circuito nel mio cervello ... L'ho confuso con qualcos'altro.
CharBuffer non funziona con i lettori e gli scrittori nel modo più pulito possibile. In particolare, non esiste un metodo Writer.append (CharBuffer buf)
. Il metodo chiamato dallo snippet di domanda è Writer.append (CharSequence seq)
, che chiama semplicemente seq.toString ()
. Il metodo CharBuffer.toString ()
restituisce il valore stringa del buffer, ma non esaurisce il buffer. La chiamata successiva a Reader.read (CharBuffer buf)
ottiene un buffer già pieno e quindi restituisce 0, costringendo il loop a continuare indefinitamente.
Sebbene questo appaia come un blocco, in realtà sta aggiungendo il contenuto del buffer della prima lettura allo scrittore ad ogni passaggio del ciclo. Quindi inizierai a vedere un sacco di output nella tua destinazione o il buffer interno dello scrittore crescerà, a seconda di come lo scrittore è implementato.
Per quanto fastidioso, consiglierei un'implementazione di char [] anche solo perché la soluzione CharBuffer finisce per costruire almeno due nuovi char [] ogni passaggio attraverso il ciclo.
public void pipe(Reader in, Writer out) throws IOException {
char[] buf = new char[DEFAULT_BUFFER_SIZE];
int count = in.read(buf);
while( count >= 0 ) {
out.write(buf, 0, count);
count = in.read(buf);
}
}
Consiglio di usarlo solo se è necessario supportare la conversione tra due codifiche di caratteri, altrimenti un'implementazione di ByteBuffer / Channel o byte [] / IOStream sarebbe preferibile anche se si stanno eseguendo il piping di caratteri.