多线程断点下载

来源:互联网 发布:淘宝卖家打快递单 编辑:程序博客网 时间:2024/05/16 13:47

本文参考:
http://www.cnblogs.com/hanyonglu/archive/2012/02/20/2358801.html
http://blog.csdn.net/lyy1104/article/details/27227001

本示例介绍在Android平台下通过HTTP协议实现断点续传下载。
主要特点:
1.多线程下载
2.支持断点。

  1. 首先获得下载文件的长度,然后设置本地文件的长度。
   int length=httpURLConnection.getContentLength();
  1. 创建本地文件+随机访问对象
  File file =new File(adFile,fileName);  RandomAccessFile accessFile=new RandomAccessFile(file,"rwd");  accessFile.setLength(fileLength);
  1. 创建多个线程+每个线程的下载任务
  for(int threadId=1;threadId<threadNum;threadId++){        int startIndex=(threadId-1)*thread*size;        int endIndex=threadId*threadsize-1;        if(threadId==threadNum){           endIndex=fileLength-1;        }  }

4.保存文件,使用RandomAccessFile类指定每条线程从本地文件的什么位置开始写入数据。

 RandomAccessFile threadfile =            new RandomAccessFile("QQWubiSetup.exe ","rwd"); threadfile.seek(2097152);//从文件的什么位置开始写入数据

示例代码:

package com.hefei.ppa.mytest.download;import android.app.Activity;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.InputStream;import java.io.RandomAccessFile;import java.net.HttpURLConnection;import java.net.URL;import android.os.Bundle;import android.os.Environment;import android.text.TextUtils;import android.view.View;import android.widget.Button;import android.widget.EditText;import android.widget.ProgressBar;import android.widget.TextView;import android.widget.Toast;import com.hefei.ppa.mytest.R;/** * Created by Administrator on 2017/1/20. */public class DownloadActivity extends Activity {    // 线程开启的数量    private int threadNum = 3;    private int threadRunning = 3;    private EditText et_url;    private ProgressBar progressBar;    private TextView tv_pb;    private Button bt_download;    private int currentProgress;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_download);        // 获取控件对象        et_url = (EditText) findViewById(R.id.et_url);        progressBar = (ProgressBar) findViewById(R.id.pb_down);        tv_pb = (TextView) findViewById(R.id.tv_pb);        bt_download= (Button) findViewById(R.id.bt_download);        File sdDir = Environment.getExternalStorageDirectory();        File pbFile = new File(sdDir,"pb.txt");        InputStream is = null;        try {            //判断文件是否存在            if (pbFile.exists()) {                is = new FileInputStream(pbFile);            }        } catch (FileNotFoundException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }        if (is != null) {            String value = StreamTools.streamToStr(is);            String[] arr = value.split(";");            progressBar.setMax(Integer.valueOf(arr[0]));//最大值            currentProgress = Integer.valueOf(arr[1]);//当前值            progressBar.setProgress(currentProgress);            tv_pb.setText("当前的进度是:"+arr[2]);//显示百分比        }        bt_download.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                downLoadFile(v);            }        });    }    // 下载文件(得到服务器端文件的大小)    public void downLoadFile(View v) {        // 获取下载路径        final String spec = et_url.getText().toString();        if (TextUtils.isEmpty(spec)) {            Toast.makeText(this, "下载的地址不能为空", Toast.LENGTH_LONG).show();        } else {            new Thread() {                public void run() {                    // HttpURLConnection                    try {                        // 根据下载的地址构建URL对象                        URL url = new URL(spec);                        // 通过URL对象的openConnection()方法打开连接,返回一个连接对象                        HttpURLConnection httpURLConnection = (HttpURLConnection) url                                .openConnection();                        // 设置请求的头                        httpURLConnection.setRequestMethod("GET");                        httpURLConnection.setReadTimeout(5000);                        httpURLConnection.setConnectTimeout(5000);                        // 判断是否响应成功                        if (httpURLConnection.getResponseCode() == 200) {                            // 获取下载文件的长度                            int fileLength = httpURLConnection                                    .getContentLength();                            //设置进度条的最大值                            progressBar.setMax(fileLength);                            //判断sd卡是否管用                            if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {                                // 保存文件                                // 外部存储设备的路径                                File sdFile = Environment                                        .getExternalStorageDirectory();                                //获取文件的名称                                String fileName = spec.substring(spec.lastIndexOf("/")+1);                                //创建保存的文件                                File file = new File(sdFile, fileName);                                //创建可以随机访问对象                                RandomAccessFile accessFile = new RandomAccessFile(                                        file, "rwd");                                // 保存文件的大小                                accessFile.setLength(fileLength);                                // 关闭                                accessFile.close();                                // 计算出每个线程的下载大小                                int threadSize = fileLength / threadNum;                                // 计算出每个线程的开始位置,结束位置                                for (int threadId = 1; threadId <= 3; threadId++) {                                    int startIndex = (threadId - 1) * threadSize;                                    int endIndex = threadId * threadSize - 1;                                    if (threadId == threadNum) {// 最后一个线程                                        endIndex = fileLength - 1;                                    }                                    System.out.println("当前线程:" + threadId                                            + " 开始位置:" + startIndex + " 结束位置:"                                            + endIndex + " 线程大小:" + threadSize);                                    // 开启线程下载                                    new DownLoadThread(threadId, startIndex,                                            endIndex, spec).start();                                }                            }else {                                DownloadActivity.this.runOnUiThread(new Runnable() {                                    public void run() {                                        Toast.makeText(DownloadActivity.this, "SD卡不管用", Toast.LENGTH_LONG).show();                                    }                                });                            }                        }else {                            //在主线程中运行                            DownloadActivity.this.runOnUiThread(new Runnable() {                                public void run() {                                    Toast.makeText(DownloadActivity.this, "服务器端返回错误", Toast.LENGTH_LONG).show();                                }                            });                        }                    } catch (Exception e) {                        // TODO Auto-generated catch block                        e.printStackTrace();                    }                };            }.start();        }    }    class DownLoadThread extends Thread {        private int threadId;        private int startIndex;        private int endIndex;        private String path;        /**         * 构造函数         *         * @param threadId         *            线程的序号         * @param startIndex         *            线程开始位置         * @param endIndex         * @param path         */        public DownLoadThread(int threadId, int startIndex, int endIndex,                              String path) {            super();            this.threadId = threadId;            this.startIndex = startIndex;            this.endIndex = endIndex;            this.path = path;        }        @Override        public void run() {            try {                File sdFile = Environment.getExternalStorageDirectory();                //获取每个线程下载的记录文件                File recordFile = new File(sdFile, threadId + ".txt");                if (recordFile.exists()) {                    // 读取文件的内容                    InputStream is = new FileInputStream(recordFile);                    // 利用工具类转换                    String value = StreamTools.streamToStr(is);                    // 获取记录的位置                    int recordIndex = Integer.parseInt(value);                    // 将记录的位置赋给开始位置                    startIndex = recordIndex;                }                // 通过path路径构建URL对象                URL url = new URL(path);                // 通过URL对象的openConnection()方法打开连接,返回一个连接对象                HttpURLConnection httpURLConnection = (HttpURLConnection) url                        .openConnection();                // 设置请求的头                httpURLConnection.setRequestMethod("GET");                httpURLConnection.setReadTimeout(5000);                // 设置下载文件的开始位置结束位置                httpURLConnection.setRequestProperty("Range", "bytes="                        + startIndex + "-" + endIndex);                // 获取的状态码                int code = httpURLConnection.getResponseCode();                // 判断是否成功                if (code == 206) {                    // 获取每个线程返回的流对象                    InputStream is = httpURLConnection.getInputStream();                    //获取文件的名称                    String fileName = path.substring(path.lastIndexOf("/")+1);                    // 根据路径创建文件                    File file = new File(sdFile, fileName);                    // 根据文件创建RandomAccessFile对象                    RandomAccessFile raf = new RandomAccessFile(file, "rwd");                    raf.seek(startIndex);                    // 定义读取的长度                    int len = 0;                    // 定义缓冲区                    byte b[] = new byte[1024 * 1024];                    int total = 0;                    // 循环读取                    while ((len = is.read(b)) != -1) {                        RandomAccessFile threadFile = new RandomAccessFile(                                new File(sdFile, threadId + ".txt"), "rwd");                        threadFile.writeBytes((startIndex + total) + "");                        threadFile.close();                        raf.write(b, 0, len);                        // 已经下载的大小                        total += len;                        //解决同步问题                        synchronized (DownloadActivity.this) {                            currentProgress += len;                            progressBar.setProgress(currentProgress);                            //计算百分比的操作 l表示long型                            final String percent = currentProgress*100l/progressBar.getMax()+"%";                            DownloadActivity.this.runOnUiThread(new Runnable() {                                public void run() {                                    tv_pb.setText("当前的进度是:"+percent);                                }                            });                            //创建保存当前进度和百分比的操作                            RandomAccessFile pbFile = new RandomAccessFile(                                    new File(sdFile, "pb.txt"), "rwd");                            pbFile.writeBytes(progressBar.getMax()+";"+currentProgress+";"+percent);                            pbFile.close();                        }                    }                    raf.close();                    is.close();                    runOnUiThread(new Runnable() {                        public void run() {                            Toast.makeText(DownloadActivity.this, "当前线程--" + threadId + "--下载完毕", Toast.LENGTH_LONG).show();                        }                    });                    deleteRecordFiles();                } else {                    runOnUiThread(new Runnable() {                        public void run() {                            Toast.makeText(DownloadActivity.this, "服务器端下载错误", Toast.LENGTH_LONG).show();                        }                    });                }            } catch (Exception e) {                // TODO Auto-generated catch block                e.printStackTrace();            }        }    }    // synchronized避免线程同步    public synchronized void deleteRecordFiles() {        File sdFile = Environment.getExternalStorageDirectory();        threadRunning--;        if (threadRunning == 0) {            for (int i = 1; i <= 3; i++) {                File recordFile = new File(sdFile, i + ".txt");                if (recordFile.exists()) {                    // 删除文件                    recordFile.delete();                }                File pbFile = new File(sdFile,"pb.txt");                if (pbFile.exists()) {                    pbFile.delete();                }            }        }    }}
0 0