Por que "tubular" um charbuffer está pendurado?
Pergunta
Por que o método seguinte está pendurado?
public void pipe(Reader in, Writer out) { CharBuffer buf = CharBuffer.allocate(DEFAULT_BUFFER_SIZE); while( in.read(buf) >= 0 ) { out.append(buf.flip()); } }
Solução
Respondendo minha própria pergunta: você tem que ligar buf.clear()
entre read
s. Presumivelmente, read
está pendurado porque o buffer está cheio. O código correto é
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(); } }
Outras dicas
Eu assumiria que é um impasse. O In.Read (BUF) bloqueia o charbuffer e evita a chamada OUT.Append (BUF).
Isso pressupõe que o CharBuffer use bloqueios (de algum tipo) na implementação. O que a API diz sobre o charbuffer da classe?
EDIT: Desculpe, algum tipo de curto -circuito no meu cérebro ... confundi com outra coisa.
Os charbuffers não trabalham com leitores e escritores da maneira mais limpa possível. Em particular, não há Writer.append(CharBuffer buf)
método. O método chamado pelo trecho de pergunta é Writer.append(CharSequence seq)
, que apenas liga seq.toString()
. o CharBuffer.toString()
O método retorna o valor da string do buffer, mas não drena o buffer. A chamada subsequente para Reader.read(CharBuffer buf)
Obtém um buffer já completo e, portanto, retorna 0, forçando o loop a continuar indefinidamente.
Embora isso pareça um jarro, está de fato anexando o conteúdo do buffer da primeira leitura ao escritor a cada passe pelo loop. Portanto, você começará a ver muita saída no seu destino ou o buffer interno do escritor crescerá, dependendo de como o escritor é implementado.
Por mais irritante que seja, eu recomendaria uma implementação de char [] apenas porque a solução de charbuffer acaba construindo pelo menos dois novos char [] cada passagem pelo loop.
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);
}
}
Eu recomendo apenas usar isso se você precisar suportar a conversão entre duas codificações de caracteres, caso contrário, uma implementação de bytebuffer/canal ou byte []/iostream seria preferível, mesmo se você estivesse canalizando caracteres.