使用servlet下载大文件

时间:2010-05-12 11:54:55

标签: java servlets file-io

我正在使用Apache Tomcat Server 6和Java 1.6,我正在尝试将大型mp3文件写入ServletOutputStream供用户下载。目前文件范围为50-750MB。

较小的文件不会造成太大的问题,但是文件较大,并且套接字异常会损坏管道。

File fileMp3 = new File(objDownloadSong.getStrSongFolder() + "/" + strSongIdName);
FileInputStream fis = new FileInputStream(fileMp3);
response.setContentType("audio/mpeg");
response.setHeader("Content-Disposition", "attachment; filename=\"" + strSongName + ".mp3\";");
response.setContentLength((int) fileMp3.length());
OutputStream os = response.getOutputStream();

try {
    int byteRead = 0;
    while ((byteRead = fis.read()) != -1) {
        os.write(byteRead);
    }
    os.flush();
} catch (Exception excp) {
    downloadComplete = "-1";
    excp.printStackTrace();
} finally {
    os.close();
    fis.close();
}

3 个答案:

答案 0 :(得分:3)

  

但是对于较大的文件,它似乎被写入堆中,然后导致OutOfMemory错误并关闭整个服务器

原因在于除了给定的代码片段之外的其他地方。其中一个原因是将整个文件读入byte[],但这似乎不会发生在您发布的代码中。此外,Tomcat 6默认情况下每2KB自动刷新一次响应流。将来请在问题中包括整个堆栈跟踪。它可能表示链中的HttpServletResponseWrapper和/或Filter可能会缓冲整个响应。

  

也让套接字异常断管。

这只是意味着对方已中止请求。从服务器端无所作为,它在技术上也应该没有害处。你可以放心地忽略它。

答案 1 :(得分:0)

你一次写出一个字节的3 / 4s文件?

尝试使用更大的缓冲区。

int BUFF_SIZE = 1024;
byte[] buffer = new byte[BUFF_SIZE];
File fileMp3 = new File(objDownloadSong.getStrSongFolder() + "/" + strSongIdName);
FileInputStream fis = new FileInputStream(fileMp3);
response.setContentType("audio/mpeg");
response.setHeader("Content-Disposition", "attachment; filename=\"" + strSongName + ".mp3\";");
response.setContentLength((int) fileMp3.length());
OutputStream os = response.getOutputStream();
int byteCount = 0;
try {
    do {
        byteCount = fis.read(buffer);
        if (byteCount == -1)
           break;
        os.write(buffer, 0, byteCount);
        os.flush();
    } while (true);
}
} catch (Exception excp) {
    downloadComplete = "-1";
    excp.printStackTrace();
} finally {
    os.close();
    fis.close();
}
顺便说一下,在我开始回答这个问题之前,我开始了一个空循环,循环750,000,000,000(你的文件大小)次,看看需要多长时间。它还在运行。

答案 2 :(得分:0)

下载大文件的一个常见问题是您正在缓冲整个文件,如果客户端不够耐心,可能会导致管道损坏。当文件太大时,您也可能在服务器上耗尽内存。

尝试通过执行此操作来强制进行分块编码,

response.setContentLength(-1);

这将导致连接器按块传输文件块。