сервлет Java, обслуживающий файл по HTTP-соединению - PullRequest
0 голосов
/ 20 октября 2010

У меня есть следующий код (Сервер Tomcat / Linux).

// Отправляем локальный файл по текущему HTTP-соединению

  FileInputStream fin = new FileInputStream(sendFile);
    int readBlockSize;
    int totalBytes=0;
    while ((readBlockSize=fin.available())>0) {                     
            byte[] buffer = new byte[readBlockSize];            
            fin.read(buffer, 0, readBlockSize);
            outStream.write(buffer, 0, readBlockSize);
            totalBytes+=readBlockSize;
    }

С некоторыми файлами типа 3gp Когда я присоединяю отладчик, в строке:

outStream.write (буфер, 0, readBlockSize);

он вспыхивает некоторое время со следующей ошибкой; Строка ApplicationFilterChain.internalDoFilter (ServletRequest, ServletResponse): 299 И файл не обслуживается.

Есть какие-нибудь подсказки? Спасибо * A.K. 1014 *

Ответы [ 3 ]

3 голосов
/ 20 октября 2010

Вы не можете гарантировать, что InputStream.read (byte [], int, int) действительно прочитает желаемое количество байтов: он может читать меньше. Даже ваш звонок в available () не дает такой гарантии. Вы должны использовать возвращаемое значение из fin.read, чтобы узнать, сколько фактически было прочитано байтов, и записать только это количество в вывод.

Я полагаю, что проблема, которую вы видите, может быть связана с этим. Если чтение блока меньше доступного размера, ваш буфер будет частично заполнен, и это приведет к проблемам, когда вы запишете слишком много байтов в вывод.

Кроме того, не выделяйте новый массив каждый раз через цикл! Это приведет к огромному количеству ненужных выделений памяти, что замедлит ваш код и потенциально вызовет OutOfMemoryError, если available() вернет большое число.

Попробуйте это:

int size;
int totalBytes = 0;
byte[] buffer = new byte[BUFFER_SIZE];
while ((size = fin.read(buffer, 0, BUFFER_SIZE)) != -1) {
    outStream.write(buffer, 0, size);
    totalBytes += size;
}
1 голос
/ 20 октября 2010

Во избежание подобных проблем я начинаю с Commons IO. Если это вариант, ваш код будет выглядеть следующим образом.

FileInputStream fin = new FileInputStream(sendFile);
int totalBytes = IOUtils.copy(fin, outStream);

Не нужно изобретать велосипед.

0 голосов
/ 20 октября 2010

Возможно, что вызов .read() вернет меньше байтов, чем вы запрашивали. Это означает, что вам нужно использовать возвращаемое значение .read() в качестве аргумента для вызова .write():

        int bytesRead = fin.read(buffer, 0, readBlockSize);
        outStream.write(buffer, 0, bytesRead);

кроме этого, лучше предварительно выделить буфер и использовать его (вы можете попробовать использовать буфер 2 Гб, если ваш файл большой: -))

byte[] buffer = new byte[4096]; // define a constant for this max length

while ((readBlockSize=fin.available())>0) {                     
    if (4096 < readBlockSize) {
        readBlockSise = 4096;
    }
...