java实现文件断点续传下载功能
本文实例为大家分享了java断点续传下载的代码,供大家参考,具体内容如下
1.Java代码    
//实现文件下载功能
publicStringdownloadFile(){
Filedir=newFile(filepath);//获取文件路劲
if(!dir.exists()){
System.out.println("文件路径错误");
log.debug("文件路径错误");
return"failed";//判断文件或文件夹是否存在
}
FiledownloadFile=newFile(dir,filename);//在指定目录下查找文件
if(!downloadFile.isFile()){
System.out.println("文件不存在");
log.debug("文件不存在");
return"failed";//判断文件或文件夹是否存在
}
try{
downloadFileRanges(downloadFile);
}catch(ClientAbortExceptione){
System.out.println("连接被终止");
log.debug("连接被终止");
}catch(IOExceptione){
e.printStackTrace();
}
returnnull;
}
privatevoiddownloadFileRanges(FiledownloadFile)throwsIOException{
//要下载的文件大小
longfileLength=downloadFile.length();
//已下载的文件大小
longpastLength=0;
//是否快车下载,否则为迅雷或其他
booleanisFlashGet=true;
//用于记录需要下载的结束字节数(迅雷或其他下载)
longlenEnd=0;
//用于记录客户端要求下载的数据范围字串
StringrangeBytes=request.getHeader("Range");
//用于随机读取写入文件
RandomAccessFileraf=null;
OutputStreamos=null;
OutputStreamoutPut=null;
byteb[]=newbyte[1024];
//如果客户端下载请求中包含了范围
if(null!=rangeBytes)
{
//返回码206
response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
rangeBytes=request.getHeader("Range").replaceAll("bytes=","");
//判断Range字串模式
if(rangeBytes.indexOf('-')==rangeBytes.length()-1)
{
//无结束字节数,为快车
isFlashGet=true;
rangeBytes=rangeBytes.substring(0,rangeBytes.indexOf('-'));
pastLength=Long.parseLong(rangeBytes.trim());
}
else
{
//迅雷下载
isFlashGet=false;
StringstartBytes=rangeBytes.substring(0,
rangeBytes.indexOf('-'));
StringendBytes=rangeBytes.substring(
rangeBytes.indexOf('-')+1,rangeBytes.length());
//已下载文件段
pastLength=Long.parseLong(startBytes.trim());
//还需下载的文件字节数(从已下载文件段开始)
lenEnd=Long.parseLong(endBytes);
}
}
//通知客户端允许断点续传,响应格式为:Accept-Ranges:bytes
response.setHeader("Accept-Ranges","bytes");
//response.reset();
//如果为第一次下载,则状态默认为200,响应格式为:HTTP/1.1200ok
if(0!=pastLength)
{
//内容范围字串
StringcontentRange="";
//响应格式
//Content-Range:bytes[文件块的开始字节]-[文件的总大小-1]||[文件的总大小]
if(isFlashGet)
{
contentRange=newStringBuffer("bytes")
.append(newLong(pastLength).toString()).append("-")
.append(newLong(fileLength-1).toString())
.append("/").append(newLong(fileLength).toString())
.toString();
}
else
{
contentRange=newStringBuffer(rangeBytes).append("/")
.append(newLong(fileLength).toString()).toString();
}
response.setHeader("Content-Range",contentRange);
}
StringfileName=getDownloadChineseFileName(filename);
response.setHeader("Content-Disposition",
"attachment;filename="+fileName+"");
//响应的格式是:
response.setContentType("application/octet-stream");
response.addHeader("Content-Length",String.valueOf(fileLength));
try
{
os=response.getOutputStream();
outPut=newBufferedOutputStream(os);
raf=newRandomAccessFile(downloadFile,"r");
//跳过已下载字节
raf.seek(pastLength);
if(isFlashGet)
{
//快车等
intn=0;
while((n=raf.read(b,0,1024))!=-1)
{
outPut.write(b,0,n);
}
}
else
{
//迅雷等
while(raf.getFilePointer()<lenEnd)
{
outPut.write(raf.read());
}
}
outPut.flush();
}
catch(IOExceptione)
{
/**
*在写数据的时候对于ClientAbortException之类的异常
*是因为客户端取消了下载,而服务器端继续向浏览器写入数据时,抛出这个异常,这个是正常的。尤其是对于迅雷这种吸血的客户端软件。
*明明已经有一个线程在读取bytes=1275856879-1275877358,
*如果短时间内没有读取完毕,迅雷会再启第二个、第三个。。。线程来读取相同的字节段,直到有一个线程读取完毕,迅雷会KILL
*掉其他正在下载同一字节段的线程,强行中止字节读出,造成服务器抛ClientAbortException。
*所以,我们忽略这种异常
*/
}
finally
{
if(outPut!=null)
{
outPut.close();
}
if(raf!=null)
{
raf.close();
}
}
}
privateStringgetDownloadChineseFileName(StringparamName)
{
StringdownloadChineseFileName="";
try
{
downloadChineseFileName=newString(paramName.getBytes("GBK"),
"ISO8859-1");
}
catch(UnsupportedEncodingExceptione)
{
e.printStackTrace();
}
returndownloadChineseFileName;
}
publicStringgetFilepath(){
returnfilepath;
}
publicvoidsetFilepath(Stringfilepath){
this.filepath=filepath;
}
publicStringgetFilename(){
returnfilename;
}
publicvoidsetFilename(Stringfilename){
this.filename=filename;
}
publicHttpServletRequestgetRequest(){
returnrequest;
}
publicHttpServletResponsegetResponse(){
returnresponse;
}
2.struts部分    
<actionname="downloadFile"class="downloadFileAction"method="downloadFile"> <resultname="failed"type="redirectAction">showDownloadFileNameList</result> </action>
3.jsp部分    
<td><ahref="downloadFile?filename=${fileMap.key}&&filepath=${fileMap.value}">文件下载</a></td>