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());
    }
}
È stato utile?

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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top