HttpURLConnection断点下载

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import android.app.Activity;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.Toast;

public class MainActivity extends Activity {

   private EditText      etPath;
   private EditText      etThread;
   private LinearLayout  llContent;
   int                   threadCount = 3;
   private String  path;

   @Override
   protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      etPath = (EditText) findViewById(R.id.et_path);
      etThread = (EditText) findViewById(R.id.et_thread);
      llContent = (LinearLayout) findViewById(R.id.ll_content);
   }

   public void download(View v) {
      path = etPath.getText().toString().trim();
      String count = etThread.getText().toString().trim();
      if (TextUtils.isEmpty(path) || !path.startsWith("http")) {
         Toast.makeText(this, "请输入正确的网址,否则,兄弟我没法干活。。。", 0).show();
         return;
      }

      if (!TextUtils.isEmpty(count)) {
         threadCount = Integer.valueOf(count);
      }

      // 移除所有的view
      llContent.removeAllViews();
      // 有多少个线程,就加载多少个进度条
      for (int i = 0; i < threadCount; i++) {
         ProgressBar pb = (ProgressBar) View.inflate(this,
                R.layout.progressbar, null);
         llContent.addView(pb);
      }
      // 开启线程
      new Thread() {
         public void run() {
            requestNet4DownLoad();
         }
      }.start();
   }

   /**
    * 下载
    */
   private void requestNet4DownLoad() {
      try {
         // 1. 在客户端创建和服务器资源一样大小的空文件
         URL url = new URL(path);
         HttpURLConnection conn = (HttpURLConnection) url.openConnection();
         conn.setConnectTimeout(3000);
         conn.setRequestMethod("GET");
         int code = conn.getResponseCode();
         // 服务器资源文件的大小
         int fileLength = 0;
         if (code == 200) {
            fileLength = conn.getContentLength();
            System.out.println("文件大小:" + fileLength);
            // //可选,可以不写,检测硬盘的空间够不够用
            // RandomAccessFile raf = new RandomAccessFile(getFilePath(),
            // "rw");
            // //在硬盘上创建控件
            // raf.setLength(fileLength);
            // raf.close();
         }
         // 每个线程下载的区块大小
         int blockSize = fileLength / threadCount;
         // 2. 客户端开启多个线程去下载服务器的资源
         for (int threadId = 0; threadId < threadCount; threadId++) {
            int startIndex = threadId * blockSize;
            int endIndex = (threadId + 1) * blockSize - 1;
            // 最后一个线程,修正下载的结束位置
            if (threadId == threadCount - 1) {
                endIndex = fileLength - 1;
            }
            // 开启线程
            new DownLoadThread(startIndex, endIndex, threadId).start();
         }
      } catch (Exception e) {
         e.printStackTrace();
      }
   }

    class DownLoadThread extends Thread {
      //开始位置
      int startIndex;
      //结束位置
      int endIndex;
      //线程ID
      int threadId;
      //断点的位置
      int lastDownPos;
      private ProgressBar   mPb;
      //最大的进度
      int maxProgress;
      //当前下载的进度
      int progress;
      //理论上开始下载的位置
      int fistIndex;
 
      public DownLoadThread(int startIndex, int endIndex, int threadId) {
         super();
         progress = startIndex;//初始化
         fistIndex = startIndex;
         this.startIndex = startIndex;
         this.endIndex = endIndex;
         this.threadId = threadId;
         lastDownPos = startIndex;//初始
         mPb = (ProgressBar) llContent.getChildAt(threadId);
         //设置最大的进度
         maxProgress = endIndex - startIndex;
         mPb.setMax(maxProgress);
      }
      @Override
      public void run() {
         super.run();
         System.out.println("理论上线程 : "+  threadId + " : "+ startIndex+" ~ "+endIndex)
         try {
            File tmpFile = new File(getFileTmpPath(threadId));
            if (tmpFile != null && tmpFile.exists() && tmpFile.length() > 0) {
                FileInputStream fis = new FileInputStream(tmpFile);
                BufferedReader br = new BufferedReader(new InputStreamReader(fis));
                int  text = Integer.valueOf(br.readLine());
                lastDownPos = text;//多次断点
                startIndex = lastDownPos; //接受上一次断点的位置请求网络           
                br.close();
                System.out.println("断点后线程 : "+  threadId + " : "+ startIndex+" ~ "+endIndex);
            }          
            URL url = new URL(path);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            conn.setConnectTimeout(3000);
            //重要,设置请求的范围

            conn.setRequestProperty("Range", "bytes="+startIndex+"-"+endIndex);

            //部分请求成功 206

            int code = conn.getResponseCode();
            System.out.println(" code = "+code);
            if (code == 206) {
                RandomAccessFile raf = new RandomAccessFile(getFilePath(), "rw");
                //重要,写文件之前定位
                raf.seek(startIndex);              
                //获取这个线程对应的一块资源
                InputStream is = conn.getInputStream();
                byte[] buffer = new byte[512];
                int len = -1;             
                while((len = is.read(buffer)) != -1){
                   //计算存储的位置
                   lastDownPos  += len;              
                  RandomAccessFile r = new RandomAccessFile(getFileTmpPath(threadId), "rwd");

                   String pos = String.valueOf(lastDownPos);
                   //存储断点的位置
                   r.write(pos.getBytes());
                   r.close();         
                   raf.write(buffer, 0, len);
                   //设置进度条的进度
                   progress = lastDownPos - fistIndex;
                   mPb.setProgress(progress);
                }          
               raf.close();
            }          
            // 3. 每个线程都下载完毕,整个资源就下载完了
            System.out.println("线程 "+threadId+" 干完活了!");
            //删除临时的进度文件
            System.out.println(tmpFile.delete());      
         } catch (Exception e) {
            e.printStackTrace();
         }
      }
   }

   /**
    * 获取文件的存储路径
    */
    String getFilePath(){
      int index = path.lastIndexOf("/")+1;
      return "/mnt/sdcard/"+path.substring(index);
   }

   **
    * 存储进度的临时文件
    */

    String getFileTmpPath(int threadId){
      return getFilePath()+threadId+".txt";
   }
}
 
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
/**
 * 操作字符串
 */

public class StringUtils {
   /**
    * 从流中转成字符串
    * 
    * @param is
    *            输入流
    * @return null表示失败
    */

   public static String parseStream2Str(InputStream is) {
      //内存输出流
      ByteArrayOutputStream baos = new ByteArrayOutputStream();
      int len = -1;
      byte[] buffer = new byte[1024*8];
      try {
         while((len = is.read(buffer)) != -1){
            baos.write(buffer, 0, len);
         }
         return new String(baos.toByteArray());
      } catch (Exception e) {
         e.printStackTrace();
         return null;
      }
   }
}

 

posted on 2017-02-23 11:05  LoaderMan  阅读(296)  评论(0编辑  收藏  举报

导航