Я использую IBM Websphere Application Server v6 и Java 1.4 и пытаюсь записать большие файлы CSV в ServletOutputStream
для загрузки пользователем. Размер файлов на данный момент составляет от 50 до 750 МБ.
Файлы меньшего размера не вызывают особых проблем, но с файлами большего размера создается впечатление, что они записываются в кучу, что приводит к ошибке OutOfMemory и отключению всего сервера.
Эти файлы могут быть предоставлены только аутентифицированным пользователям через HTTPS, поэтому я передаю их через сервлет, а не просто прикрепляю их в Apache.
Код, который я использую (некоторый пух удален вокруг этого):
resp.setHeader("Content-length", "" + fileLength);
resp.setContentType("application/vnd.ms-excel");
resp.setHeader("Content-Disposition","attachment; filename=\"export.csv\"");
FileInputStream inputStream = null;
try
{
inputStream = new FileInputStream(path);
byte[] buffer = new byte[1024];
int bytesRead = 0;
do
{
bytesRead = inputStream.read(buffer, offset, buffer.length);
resp.getOutputStream().write(buffer, 0, bytesRead);
}
while (bytesRead == buffer.length);
resp.getOutputStream().flush();
}
finally
{
if(inputStream != null)
inputStream.close();
}
Кажется, что FileInputStream
не вызывает проблемы, как будто я пишу в другой файл или просто полностью удаляю запись, использование памяти не является проблемой.
Я думаю, что resp.getOutputStream().write
сохраняется в памяти до тех пор, пока данные не будут отправлены клиенту. Таким образом, весь файл может быть прочитан и сохранен в resp.getOutputStream()
, что вызывает проблемы с памятью и приводит к сбою!
Я пытался буферизовать эти потоки, а также пытался использовать каналы из java.nio
, ни один из которых, кажется, не имеет никакого значения для моей памяти. Я также сбросил OutputStream
один раз за итерацию цикла и после цикла, что не помогло.