zoukankan      html  css  js  c++  java
  • 基于HTTP协议的下载功能实现

      超文本传输协议 (HTTP-HyperText Transfer Protocol)是一种使用极为广泛的协议,它由请求和响应构成,是一种无状态的应用层协议。设计HTTP协议的初衷是为了提供一种传输HTML(HyperText Markup Language,超文本标记语言)的协议和方法。通过HTTP协议请求的资源由URI(Uniform Resource Identifiers,统一资源标识符)来标识。通常,我们通过URI就能访问到万维网服务器提供的数据,如HTML文档、音视频等各种格式的数据。因此,基于HTTP协议,我们可以实现简单的下载器功能。

      HTTP下载器的功能很简单,下载器使用指定的URI发送GET请求到服务器,服务器返回请求响应,下载器根据响应状态码判断请求成功与否。一般情况下,请求一个资源成功后的状态码应为200(HTTP_OK)或者206(Partial-Content)。其他状态码视为失败(具体的HTTP状态码请参见:http://zh.wikipedia.org/wiki/HTTP%E7%8A%B6%E6%80%81%E7%A0%81)。若请求成功,HTTP响应头中将会带有资源的相关信息,其中,我们最关心的是资源大小,一般以Content-Length字段返回(HTTP头字段请参考:http://msdn.microsoft.com/zh-cn/library/aa287673(v=vs.71).aspx),若有Range字段的情况下,也可以通过Range字段的返回值来计算得到资源的大小,这里的资源大小单位为byte。

      下面就以Java语言来实现一个基于HTTP协议的下载器。因测试工程是为项目所编写,实现了一套完整的下载管控机制(如下载记录管理、多任务管理、断点续下、意外中断自动恢复下载、状态通知等功能),为保密起见,以下只公开下载部分核心代码:

      下载状态类:

    public class Status {
    public static final int ERROR = -1; public static final int WAITING = 0; /** * Paused by system automatically */ public static final int PAUSED = 1; /** * Paused by user manually */ public static final int PAUSED_MANUALLY = 2; public static final int DOWNLOADING = 3; public static final int FINISHED = 4; }

      下载类:

    package com.irwin.downloader;
    
    import java.io.File;
    import java.io.InputStream;
    import java.io.RandomAccessFile;
    import java.net.HttpURLConnection;
    import java.net.URL;
    
    import org.apache.http.HttpStatus;
    
    
    public class Downloader implements Runnable {
        private static final int BUFFER_SIZE = 32 * 1024;
    
        private String mUrl = null;
    
        private String mPath = null;
    
        private long mStart = 0;
    
        private long mCurrentBytes = 0;
    
        private int mStatus = Status.WAITING;
    
        private long mSize = 0;
    
        private boolean mRunning = true;
    
        private boolean mTerminate = false;
    
        public void setUrl(String url) {
            mUrl = url;
        }
    
        public String getUrl() {
            return mUrl;
        }
    
        public void setPath(String path) {
            mPath = path;
        }
    
        public String getPath() {
            return mPath;
        }
    
        public void setRange(long start, long end) {
            if (start >= 0) {
                mStart = start;
            }
            mSize = end;
        }
    
        public void setTerminate(boolean terminate) {
            mTerminate = terminate;
        }
    
        public boolean isRunning() {
            return mRunning;
        }
    
        public int getStatus() {
    
            return mStatus;
        }
    
        public long getSize() {
            return mSize;
        }
    
        public long getCurrentBytes() {
            return mCurrentBytes;
        }
    
        public void download(String url, String path, long rangeStart)
                throws Exception {
            if (rangeStart > 0 && rangeStart >= mSize) {
                mStatus = Status.FINISHED;
                return;
            }
            InputStream inStream = null;
            RandomAccessFile file = null;
            try {
                URL downUrl = new URL(url);
                HttpURLConnection http = (HttpURLConnection) downUrl
                        .openConnection();
                http.setConnectTimeout(5 * 1000);
                //Use Get method
                http.setRequestMethod("GET");
                //Accept all format of data.
                http.setRequestProperty("Accept", "*/*");
                http.setRequestProperty("Charset", "UTF-8");
                
                //Data block to download. 
                http.setRequestProperty("Range", "bytes=" + rangeStart + "-");
                http.setRequestProperty("User-Agent", "Client/4.0");
                http.setRequestProperty("Connection", "Keep-Alive");
                http.connect();
                if (http.getResponseCode() != HttpStatus.SC_OK
                        && http.getResponseCode() != HttpStatus.SC_PARTIAL_CONTENT) {
                    throw new IllegalAccessException("Invalid request: "
                            + http.getResponseCode());
                }
                if (mSize <= 0) {
                    long total = getContentLen(http);
    
                    if (total <= 0) {
                        throw new IllegalAccessException("Invalid content-length: "
                                + total);
                    }
                    mSize = total;
                }
                mStatus = Status.DOWNLOADING;
                inStream = http.getInputStream();
                byte[] buffer = new byte[BUFFER_SIZE];
    File tmp=new File(path+".tmp"); file
    = new RandomAccessFile(tmp, "rwd"); file.setLength(mSize); file.seek(rangeStart); int offset = 0; mCurrentBytes = rangeStart; while (true) { if (mTerminate) { mStatus = Status.PAUSED_MANUALLY; break; } if ((offset = inStream.read(buffer)) != -1) { file.write(buffer, 0, offset); mCurrentBytes += offset; } else { break; } } file.close(); file = null; inStream.close(); inStream = null; if (mSize == mCurrentBytes) { // Rename mStatus = Status.FINISHED; File f = new File(path); tmp.renameTo(f); } } catch (Exception e) { throw e; } finally { if (inStream != null) { try { inStream.close(); } catch (Exception e2) { // TODO: handle exception } } if (file != null) { try { file.close(); } catch (Exception e2) { // TODO: handle exception } } } } @Override public void run() { if (getUrl() != null && getPath() != null) { if (!mTerminate) { try { download(getUrl(), getPath(), mStart); } catch (Exception e) { e.printStackTrace(); mStatus = Status.ERROR; } } } else { mStatus = Status.ERROR; } mRunning = false; } private long getContentLen(HttpURLConnection conn) throws Exception { long len = conn.getContentLength(); if (len <= 0) { try { len = Long.parseLong(conn.getHeaderField("Content-Length")); } catch (Exception e) { // TODO: handle exception } } if (len <= 0) { //Try to calculate size from 'Range' field. String range = conn.getHeaderField("Range"); if (range != null) { String[] array = range.replace("bytes=", "").split("-"); if (array.length == 2) { len = Long.parseLong(array[1]) - Long.parseLong(array[0]); } } } return len; } }

     更多代码详情请参考:TransferLibrary——一个Android文件传输库,主要实现基于Http的文件上传和下载,简单方便,支持多任务下载,断点续传等等,欢迎小伙伴们使用交流:D

  • 相关阅读:
    GCD与LCM
    命名空间的使用
    [模板][持续更新]欧拉回路与欧拉路径浅析
    二进制GCD算法解析
    [模板]LCA的倍增求法解析
    [模板]字符串哈希的简易做法
    11、Android--屏幕适配
    10、Android--Shape
    09、Android--Fragment
    08、Android--BroadcastReceiver
  • 原文地址:https://www.cnblogs.com/oxgen/p/HttpDownloader.html
Copyright © 2011-2022 走看看