断点续传(客户端和服务器端实现)

来源:互联网 发布:中科大算法导论 编辑:程序博客网 时间:2024/06/06 05:49

断点续传(客户端和服务器端实现)

4360人阅读 评论(4)收藏举报
本文章已收录于:
分类:
作者同类文章X

    所谓断点续传,也就是要从文件已经下载的地方开始继续下载。

    客户端从服务器端下载文件,服务器端支持分段下载,这样子,还可以进行多线程分段下载(在此就不提供了)。

    服务器端的支持:

    [java] view plain copy print?
    1. public class DownloadServlet extends HttpServlet {  
    2.   
    3.     /** 
    4.      *  
    5.      */  
    6.     private static final long serialVersionUID = 1L;  
    7.       
    8.     protected void doGet(HttpServletRequest req, HttpServletResponse resp)  
    9.             throws ServletException, IOException {  
    10.         // TODO Auto-generated method stub  
    11.         OutputStream os = null;  
    12.         FileInputStream is = null;  
    13.         try {  
    14.             File f = new File(  
    15.                     "/home/agilemobi/Desktop/laolian_client_for_android_v1.0.apk");  
    16.             is = new FileInputStream(f);  
    17.             long fileSize = f.length();  
    18.             resp.setHeader("Accept-Ranges""bytes");  
    19. //          resp.setHeader("Content-Length", fileSize + "");  
    20.             String range = req.getHeader("Range");  
    21.             int status = HttpServletResponse.SC_OK; // 返回的状态码,默认200,首次下载  
    22.             // 如果range下载区域为空,则首次下载,  
    23.             if(range == null){  
    24.                 range = "bytes=0-";  
    25.             } else {  
    26.                 // 通过下载区域下载,使用206状态码支持断点续传  
    27.                 status = HttpServletResponse.SC_PARTIAL_CONTENT;  
    28.             }  
    29.               
    30.             long start = 0, end = 0;  
    31.             if (null != range && range.startsWith("bytes=")) {  
    32.                 String[] values = range.split("=")[1].split("-");  
    33.                 start = Integer.parseInt(values[0]);  
    34.                 // 如果服务器端没有设置end结尾,默认取下载全部  
    35.                 if(values.length == 1){  
    36.                     end = fileSize;  
    37.                 } else {  
    38.                     end = Integer.parseInt(values[1]);  
    39.                 }  
    40.                    
    41.             }  
    42.             // 此次数据响应大小  
    43.             long responseSize = 0;  
    44.             if (end != 0 && end > start) {  
    45.                 responseSize = end - start + 1;  
    46.                 // 返回当前连接下载的数据大小,也就是此次数据传输大小  
    47.                 resp.addHeader("Content-Length""" + (responseSize));  
    48.             } else {  
    49.                 responseSize = Integer.MAX_VALUE;  
    50.             }  
    51.               
    52.             byte[] buffer = new byte[4096];  
    53.             // 设置响应状态码  
    54.             resp.setStatus(status);  
    55.             if(status == HttpServletResponse.SC_PARTIAL_CONTENT){  
    56.                 // 设置断点续传的Content-Range传输字节和总字节  
    57.                 resp.addHeader("Content-Range""bytes " + start + "-" + (fileSize - 1) + "/" + fileSize);  
    58.             }  
    59.             // 设置响应客户端内容类型  
    60.             resp.setContentType("application/x-download");  
    61.             // 设置响应客户端头  
    62.             resp.addHeader("Content-Disposition""attachment;filename=laolian_client_for_android_v1.0.apk");  
    63.             // 当前需要下载文件的大小  
    64.             int needSize = (int)responseSize;  
    65.             if(start != 0){  
    66.                 // 跳已经传输过的字节  
    67.                 is.skip(start);  
    68.             }  
    69.             os = resp.getOutputStream();  
    70.             while (needSize > 0) {  
    71.                 int len = is.read(buffer);  
    72.                 if (needSize < buffer.length) {  
    73.                     os.write(buffer, 0, needSize);  
    74.                 } else {  
    75.                     os.write(buffer, 0, len);  
    76.                     // 如果读取文件大小小于缓冲字节大小,表示已写入完,直接跳出  
    77.                     if (len < buffer.length) {  
    78.                         break;  
    79.                     }  
    80.                 }  
    81.                 // 不断更新当前可下载文件大小  
    82.                 needSize -= buffer.length;  
    83.             }  
    84.         } catch (IOException e) {  
    85.             e.printStackTrace();  
    86.             return;  
    87.         } finally {  
    88.             if (is != null)  
    89.                 is.close();  
    90.             if (os != null)  
    91.                 os.close();  
    92.         }  
    93.     }  
    94.   
    95.     @Override  
    96.     protected void doPost(HttpServletRequest req, HttpServletResponse resp)  
    97.             throws ServletException, IOException {  
    98.         // TODO Auto-generated method stub  
    99.         super.doPost(req, resp);  
    100.           
    101.     }  
    102.   
    103. }  



    客户端:

    [java] view plain copy print?
    1. public class TestConn {  
    2.   
    3.     /** 
    4.      * @param args 
    5.      * @throws IOException  
    6.      */  
    7.     public static void main(String[] args) throws IOException {  
    8.         // TODO Auto-generated method stub  
    9.         String urlstr = "http://localhost:8090/mydownload/DownloadServlet";  
    10.         URL url = new URL(urlstr);  
    11.         HttpURLConnection connection = (HttpURLConnection) url  
    12.                 .openConnection();  
    13.         connection.setConnectTimeout(5000);  
    14.         connection.setRequestMethod("GET");  
    15.           
    16. //      connection.setRequestProperty("Accept-Encoding", "identity");  
    17.         connection.connect();  
    18.           
    19.         int fileSize = connection.getContentLength();  
    20.         System.out.println(connection.getResponseCode());  
    21.         System.out.println(fileSize);  
    22.         connection.disconnect();  
    23.   
    24.         download(0020000, urlstr);  
    25.     }  
    26.       
    27.       
    28.     private static void download(int startPos, int compeleteSize, int endPos, String urlstr){  
    29.         HttpURLConnection connection = null;  
    30.         RandomAccessFile randomAccessFile = null;  
    31.         InputStream is = null;  
    32.         try {  
    33.             URL url = new URL(urlstr);  
    34.             connection = (HttpURLConnection) url.openConnection();  
    35.             connection.setConnectTimeout(5000);  
    36.             connection.setRequestMethod("GET");  
    37.             // 设置范围,格式为Range:bytes x-y;  
    38.             connection.setRequestProperty("Range""bytes="  
    39.                     + (startPos + compeleteSize) + "-" + endPos);  
    40.   
    41.             randomAccessFile = new RandomAccessFile("/home/agilemobi/Desktop/1.apk""rwd");  
    42.             randomAccessFile.seek(startPos + compeleteSize);  
    43.             // 将要下载的文件写到保存在保存路径下的文件中  
    44.             is = connection.getInputStream();  
    45.             byte[] buffer = new byte[4096];  
    46.             int length = -1;  
    47.             while ((length = is.read(buffer)) != -1) {  
    48.                 randomAccessFile.write(buffer, 0, length);  
    49.                 compeleteSize += length;  
    50.                 System.out.println("compeleteSize:" + compeleteSize);  
    51.             }  
    52.             System.out.println("OVER:" + compeleteSize);  
    53.         } catch (Exception e) {  
    54.             e.printStackTrace();  
    55.         } finally {  
    56.             try {  
    57.                 if(is != null)  
    58.                     is.close();  
    59.                 if(randomAccessFile != null)  
    60.                     randomAccessFile.close();  
    61.                 if(connection != null)  
    62.                     connection.disconnect();  
    63.             } catch (Exception e) {  
    64.                 e.printStackTrace();  
    65.             }  
    66.         }  
    67.     }  
    68.   
    69. }  

    关键点:
    客户端

    1.

    [java] view plain copy print?
    1. connection.setRequestProperty("Range""bytes="  
    2.                     + (startPos + compeleteSize) + "-" + endPos);  
    2.
    [java] view plain copy print?
    1. RandomAccessFile的使用  


    服务器端

    1.对HTTP头Range信息的解析。

    2.InputStream的skip()跳过多少字节流。

    3.状态的设置。

    4.Content-Length的设置,否则客户端getContentLength()返回为-1。

    [java] view plain copy print?
    1. resp.addHeader("Content-Length""" + (responseSize));  

    1
    0
     
     

    我的同类文章

    http://blog.csdn.net
    • 金额转大写2015-12-23
    • jsp 页面静态化 java.net.MalformedURLException: no protocol: index.jsp和java.net.MalformedURLException: unknown protocol: d2010-04-18
    • 将.class文件打包成jar文件2009-09-04
    • android表单上传出现java.lang.NoClassDefFoundError2012-04-24
    • (利用键值对)java中打印集合中字符出现次数2009-10-21

    参考知识库

    更多资料请参考:
    猜你在找
    全网服务器数据备份解决方案案例实践
    Nginx服务器入门
    EasyDarwin开源流媒体服务器:编译、配置、部署
    2016软考网络工程师信道数据传输速率与码元速率强化训练教程
    征服JavaScript高级程序设计与应用实例视频课程
    FTP客户端实现断点续传
    使用orgapachecommonsnetftp包开发FTP客户端实现进度汇报实现断点续传中文支持
    使用orgapachecommonsnetftp包开发FTP客户端实现进度汇报实现断点续传中文支持
    使用orgapachecommonsnetftp包开发FTP客户端实现进度汇报实现断点续传中文支持
    使用orgapachecommonsnetftp包开发FTP客户端实现进度汇报实现断点续传中文支持
    查看评论
    4楼 A2328295142016-09-14 17:00发表 [回复] [引用][举报]
    Content-Length: [文件的总大小] - [客户端请求的下载的文件块的开始字节]
    所以responseSize = end - start ,不是 end - start+1,不然下载的文件与原文件作MD5比较或直接输出大小会发现已经不是同个文件
    3楼 A2328295142016-09-14 16:59发表 [回复] [引用][举报]
    Content-Length: [文件的总大小] - [客户端请求的下载的文件块的开始字节]
    所以responseSize = end - start ,不是 end - start+1,不然下载的文件与原文件作MD5比较或直接输出大小会发现已经不是同个文件
    2楼 Java职业不再难2015-12-25 12:27发表 [回复] [引用][举报]
    好文章


    0 0
    原创粉丝点击