Почему «перекачивание» CharBuffer зависает?
Вопрос
Почему следующий метод зависает?
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()
между read
с.Предположительно, read
зависает, потому что буфер заполнен.Правильный код:
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(); } }
Другие советы
Я бы предположил, что это тупик.in.read(buf) блокирует CharBuffer и предотвращает вызов out.append(buf).
Это предполагает, что CharBuffer использует блокировки (какие-то) в реализации.Что говорит API о классе CharBuffer?
Редактировать:Извините, какое-то замыкание в мозгу...Я спутал это с чем-то другим.
CharBuffers не работают с устройствами чтения и записи так четко, как можно было бы ожидать.В частности, нет Writer.append(CharBuffer buf)
метод.Метод, вызываемый фрагментом вопроса, Writer.append(CharSequence seq)
, который просто вызывает seq.toString()
.А CharBuffer.toString()
Метод возвращает строковое значение буфера, но не опустошает буфер.Последующий вызов Reader.read(CharBuffer buf)
получает уже полный буфер и поэтому возвращает 0, заставляя цикл продолжаться бесконечно.
Хотя это похоже на зависание, на самом деле это добавляет содержимое буфера первого чтения к записывающему устройству при каждом проходе цикла.Таким образом, вы либо начнете видеть большой объем вывода в пункте назначения, либо внутренний буфер средства записи будет расти, в зависимости от того, как реализован модуль записи.
Как бы это ни досадно, я бы порекомендовал реализацию char[] хотя бы потому, что решение CharBuffer создает как минимум два новых char[] при каждом проходе цикла.
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);
}
}
Я бы рекомендовал использовать это только в том случае, если вам нужно поддерживать преобразование между двумя кодировками символов, в противном случае реализация ByteBuffer/Channel или byte[]/IOStream будет предпочтительнее, даже если вы передаете символы по конвейеру.