Вот ссылка, которая предлагает несколько вариантов. Я искал простую спецификацию, которой я мог следовать, вместо того, чтобы полагаться на частично определенный.
Средний приличный контейнер сервлетов очищает поток по умолчанию каждые ~ 2 КБ. Вам действительно не нужно явно вызывать flush ()
в OutputStream
из HttpServletResponse
через определенные промежутки времени при последовательной потоковой передаче данных из одного и того же источника. Например, в Tomcat (и Websphere!) Это можно настроить как атрибут bufferSize
коннектора HTTP.
Средний приличный контейнер сервлетов также просто передает данные в фрагментах , если длина содержимого заранее неизвестна (согласно спецификации API сервлетов !) И если клиент поддерживает HTTP 1.1.
По крайней мере, симптомы проблемы указывают на то, что контейнер сервлетов буферизует весь поток в памяти перед сбросом. Это может означать, что заголовок длины содержимого не установлен и / или контейнер сервлетов не поддерживает фрагментированное кодирование и / или клиентская сторона не поддерживает фрагментированное кодирование (то есть использует HTTP 1.0).
Чтобы исправить то или иное, просто заранее установите длину содержимого:
response.setHeader("Content-Length", String.valueOf(new File(path).length()));
Делает flush
работа над потоком вывода.
Действительно я хотел прокомментировать, что необходимо использовать форму с тремя аргументами записи, поскольку буфер не обязательно полностью читается (особенно в конце файла (!)). Также попытка/наконец была бы в порядке, если Вы не хотите, чтобы Вы сервер неожиданно умерли.
Я использовал класс, который переносит outputstream для создания этого допускающим повторное использование в других контекстах. Это работало хорошо на меня в получении данных к браузеру быстрее, но я не посмотрел на последствия памяти. (простите мое устаревшее m_ именование переменной),
import java.io.IOException;
import java.io.OutputStream;
public class AutoFlushOutputStream extends OutputStream {
protected long m_count = 0;
protected long m_limit = 4096;
protected OutputStream m_out;
public AutoFlushOutputStream(OutputStream out) {
m_out = out;
}
public AutoFlushOutputStream(OutputStream out, long limit) {
m_out = out;
m_limit = limit;
}
public void write(int b) throws IOException {
if (m_out != null) {
m_out.write(b);
m_count++;
if (m_limit > 0 && m_count >= m_limit) {
m_out.flush();
m_count = 0;
}
}
}
}
Я также не уверен если flush()
на ServletOutputStream
работы в этом случае, но ServletResponse.flushBuffer()
должен отправить ответ клиенту (по крайней мере, на 2,3 спецификации сервлета).
ServletResponse.setBufferSize()
обещание звуков, также.
не связанный с Вашими проблемами памяти, цикл с условием продолжения должен быть:
while(bytesRead > 0);
Итак, следуя вашему сценарию, разве вы не должны сбрасывать данные внутри цикла while (на каждой итерации), а не за его пределами? Я бы попробовал это, хотя и с немного большим буфером.
Класс Кевина должен закрывать поле m_out
, если оно не равно null в операторе close(), мы же не хотим утечки информации?
Помимо оператора ServletOutputStream.flush()
, операция HttpServletResponse.flushBuffer()
также может очищать буферы. Однако, похоже, что это специфическая деталь реализации, имеют ли эти операции какой-либо эффект, или поддержка длины http-контента мешает. Помните, что указание длины содержимого - это опция в HTTP 1.0, так что все должно быть просто потоком, если вы все промываете. Но я не вижу этого