Почему следующий метод зависает?Почему «трубопровод» CharBuffer висит?
public void pipe(Reader in, Writer out) { CharBuffer buf = CharBuffer.allocate(DEFAULT_BUFFER_SIZE); while(in.read(buf) >= 0) { out.append(buf.flip()); } }
Почему следующий метод зависает?Почему «трубопровод» 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 завершает строительство по меньшей мере двух новых символов [] каждый проход через цикл.
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/канал или байт реализации []/IOStream бы предпочтительнее, даже если вы трубопроводные символы.
Подвеска? Глядя на читаемый API, я бы ожидал, что он занят циклом, возвращающим 0 на каждый прочитанный, если буфер заполнен, но это предположение, поскольку в нем явно не указано, что означает «попытки прочитать». Висячие могут означать, что, поскольку вы многократно записываете выходные данные, вы заблокировали вывод. –
Я не проверял подробное поведение цикла. Либо считывает блоки, либо повторно возвращает 0. Сетевой эффект: цикл никогда не заканчивается. –
Я предполагаю, что для блокировки выходного потока должно быть что-то с конечной емкостью, которая не сливается, как круговой буфер - довольно редкий случай. Возможно, я особенный, потому что я обычно использую «зависание», чтобы означать «тупик», а не «живой». –