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>