多线程下载文件

最近看了下多线程下载文件,下载总结一下。

原理:

1.首先访问服务器端,获取到需要下载文件的总大小,并在本地创建同样大小的空白文件;这一步很简单,用你熟悉的任何一种网络访问方法,访问服务器都可以,请求成功后获取内容长度,之后利用RandomAccessFile这个类,创建空白文件,把内容长度设置为文件大小。

2.等分任务,计算出每个线程的开始下载位置以及结束下载位置;根据步骤1中获取到的文件长度,除上想要开启的线程总数,求得的整数为每个线程的下载任务大小blockSize,开始下载位置=i*blockSize(i从0开始),停止下载位置=(i+1)*blockSize-1.



3.开启多个线程,为每个线程设置开始下载的位置以及结束下载位置;这一步就开始请求服务器进行真正的文件下载了,需要注意的就是要设置网络请求时的开始位置和停止位置setRequestProperty("Range", "bytes="+startIndext+"-"+endIndext);,responsecode不是200而是206,之后还是利用RandomAccessFile类的seek方法设置文件写入的位置,write方法进行文件的写入。


代码:

package com.example.multhread;

import android.app.Activity;
import android.os.Environment;
import android.util.Log;
import android.widget.Toast;

import java.io.File;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by pactera on 2017/2/4.
 */

public class DownloadManager {
    private static final String path = "http://10.5.92.12:8080/loginProject/gg.exe";
    private static final String TAG = "DownloadManager";
    private static final int ThreadSize = 3;
    private Activity activity;
    private List<MyThread> threads;

    public DownloadManager(Activity activity) {
        this.activity = activity;
        threads = new ArrayList<MyThread>();
    }

    public void StartDownload () {
        //1.在Android客户端首先创建一个和需要下载的文件相同大小的空白文件
        long fileSize = getFileSize();
        //2.开启3个线程去下载对应文件
        if (fileSize > 0) {
            startMutileThread(fileSize);
            //3.如果所有线程都下载完毕,服务器的资源就下载完毕了
            ifDownLoadSuccess();
        } else {
            ToastOnScreen("服务器访问异常,请稍后再试");
        }
    }

    private long getFileSize() {
        try {
            URL url = new URL(path);
            HttpURLConnection con = (HttpURLConnection) url.openConnection();
            con.setRequestMethod("GET");
            con.setConnectTimeout(5000);
            int code = con.getResponseCode();

            if (code == 200) {
                long size = con.getContentLength();//获取文件长度
                Log.d(TAG,"文件大小为:"+size);
                File f = new File(Environment.getExternalStorageDirectory(),"gg.exe");
                RandomAccessFile file = new RandomAccessFile(f,"rwd");//在本地创建文件
                file.setLength(size);//将要下载的文件长度,赋给本地文件
                file.close();
                return size;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }

    private void startMutileThread(long fileSize) {
        long size = fileSize/ThreadSize;//获取每个线程需要下载文件的长度
        for (int i=0; i<ThreadSize; i++) {
            long startIndex = i*size;//计算每个线程开始下载文件的位置
            long endIndex = (i+1)*size-1;//停止下载文件的位置

            if (i==ThreadSize-1) {//如果是最后一个线程,则直接下载完剩余的文件
                endIndex = fileSize-1;
            }

            MyThread thread = new MyThread(startIndex,endIndex);//开启线程
            threads.add(thread);
            thread.start();
        }
    }

    private class MyThread extends Thread {
        private long startIndex;
        private long endIndex;

        public MyThread(long startIndex, long endIndex) {
            this.startIndex = startIndex;//开始下载的位置
            this.endIndex = endIndex;//停止下载的位置
            Log.d(TAG,startIndex+"-"+endIndex+"部分文件开始下载!");
        }

        @Override
        public void run() {
            super.run();
            try {
                URL url = new URL(path);
                HttpURLConnection con = (HttpURLConnection) url.openConnection();
                con.setRequestMethod("GET");
                con.setRequestProperty("Range","bytes="+startIndex+"-"+endIndex);//设置请求头,设置开始下载位置和停止位置
                con.setConnectTimeout(5000);
                int code = con.getResponseCode();

                if (code == 206) {//分段下载的返回码是206不是200
                    InputStream is = con.getInputStream();
                    File f = new File(Environment.getExternalStorageDirectory(),"gg.exe");
                    RandomAccessFile file = new RandomAccessFile(f,"rw");//在本地创建文件
                    file.seek(startIndex);
                    int len;
                    byte[] buffer = new byte[1024];
                    while ((len = is.read(buffer)) != -1) {
                        file.write(buffer,0,len);
                    }
                    is.close();
                    file.close();
                    Log.d(TAG,startIndex+"-"+endIndex+"部分文件下载完毕!");
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    private void ifDownLoadSuccess() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(2000);
                    int closeThread = 0;
                    for (MyThread t:threads) {
                        if (!t.isAlive()) {
                            closeThread++;
                        }
                    }

                    if (closeThread == ThreadSize) {
                        ToastOnScreen("下载完成");
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    private void ToastOnScreen(final String s) {
        activity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(activity, s, Toast.LENGTH_LONG).show();
            }
        });
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值