我正在使用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();
}
答案 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);
这将导致连接器按块传输文件块。