web大文件下載+斷點續傳


實現原理
(1)首先獲得下載文件的長度,然后設置本地文件的長度。
(2)根據文件長度和線程數計算每條線程下載的數據長度和下載位置。
如:文件的長度為6M,線程數為3,那么,每條線程下載的數據長度為2M,每條線程開始下載的位置如下圖所示:
?例如10M大小,使用3個線程來下載,
線程下載的數據長度 ? (10%3 == 0 ? 10/3:10/3+1) ,第1,2個線程下載長度是4M,第三個線程下載長度為2M
下載開始位置:線程id*每條線程下載的數據長度 = ?
下載結束位置:(線程id+1)*每條線程下載的數據長度-1=?

Activity代碼

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    @SuppressLint("HandlerLeak")
    public static Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            int size = msg.getData().getInt("size");
//            progressbar.setProgress();
            float temp = (float) size / (float)progressbar.getMax();
            int progress = (int) (temp * 100);
            if (progress == 100) {
                Log.e("TAG", "handleMessage: " + "下載完成");
            }
            tv_result.setText("下載進度:" + progress + "%");
        }
    };
    private EditText ed;
    private Button btn_download;
    private static ProgressBar progressbar;
    private static TextView tv_result;
    private String urlstring;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
    }
 
    private void initView() {
        ed = (EditText) findViewById(R.id.ed);
        btn_download = (Button) findViewById(R.id.btn_download);
        progressbar = (ProgressBar) findViewById(R.id.progressbar);
        tv_result = (TextView) findViewById(R.id.tv_result);
 
 
        btn_download.setOnClickListener(this);
    }
 
 
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_download:
                submit();
                download();
                break;
        }
    }
 
    //下載文件
    private void download() {
//獲取sd卡路徑
        String path = Environment.getExternalStorageDirectory() + "/morethreaddownload/";
        File file = new File(path);
        if (!file.exists()) {
//            如果文件目錄不存在,就創建此文件夾
            file.mkdir();
        }
 
 
//      指定下載的大文件的名稱
        String filename = "fulin.apk";
//        要下載的文件路徑
        String filepath = path + filename;
//        線程的數量
        int threadcount = 5;
 
 
//  開啟子線程下載文件(獲取文件的長度)
        DownLoadTask task = new DownLoadTask(progressbar,urlstring,filepath,threadcount);
        task.start();
    }
    private void submit() {
//輸入框中用戶輸入的網絡路徑
        urlstring = ed.getText().toString().trim();
        if (TextUtils.isEmpty(urlstring)) {
            Toast.makeText(this, "edString不能為空", Toast.LENGTH_SHORT).show();
            return;
        }
    }
 
}
DownLoadTask類

public class DownLoadTask extends Thread {
    //     網路文件的下載地址
    private String downloadUrl;
    //    保存文件的路徑
    private String filePath;
    //    線程的數量
    private int threadcount;
//    進度條
    private ProgressBar  progressBar;
//    文件的大小
    public static int filesize;
    //    每個線程的下載量
    private int blockSize;
//構造方法
    public DownLoadTask(ProgressBar  progressBar, String downloadUrl, String filePath, int threadcount) {
        this.progressBar=progressBar;
        this.downloadUrl = downloadUrl;
        this.filePath = filePath;
        this.threadcount = threadcount;
    }
 
    @Override
    public void run() {
        super.run();
//        線程數組
        FileDownloadThread[] threads = new FileDownloadThread[threadcount];
        try {
            URL url = new URL(downloadUrl);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.connect();
            if (conn.getResponseCode() == 200) {
//                讀取下載文件的總長度
                filesize = conn.getContentLength();
                if (filesize <= 0) {
                    Log.e(TAG, "run: " + "讀取文件失敗");
                    return;
                }
 
//                設置progressbar的最大值
                progressBar.setMax(filesize);
//
//              計算每條線程下載的數據長度
                blockSize = filesize % threadcount == 0 ? filesize / threadcount : filesize / threadcount + 1;
//sd卡里邊指定的保存網絡端下載下來的文件
                File file = new File(filePath);
//                啟動每個線程,分別下載所分配的長度
                for (int i = 0; i < threadcount; i++) {
                    threads[i] = new FileDownloadThread(file,url,(i+1),blockSize);
                    threads[i].setName("Thread:" + i);
                    threads[i].start();
                }
//是否下載完成
                boolean isfinished = false;
//                下載的總長度
                int downloadAllsize = 0;
                while (!isfinished) {
                    isfinished = true;
                    downloadAllsize = 0;
                    for (int i = 0; i < threadcount; i++) {
                        downloadAllsize += threads[i].getDownloadlenght();
                        if (!threads[i].isCompleted()) {
                            isfinished = false;
                        }
                    }
//                    通知handler去更新
                    Message message = new Message();
                    message.getData().putInt("size", downloadAllsize);
                    MainActivity.handler.sendMessage(message);
                    Thread.sleep(1000);
                }
                Log.e(TAG, "run:下載的總大小: "+ downloadAllsize);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
class FileDownloadThread extends Thread {
    /**
     *  文件保存路徑 
     */
    private File file;
    /**
     *  文件下載路徑 (文件網址)
     */
    private URL downloadUrl;
    /**
     *  當前下載線程ID 
     */
    private int threadId;
    /**
     *  線程下載數據長度 
     */
    private int blockSize;
    private int downloadlenght;
    private boolean isCompleted;
 
    public FileDownloadThread(File file, URL downloadUrl, int threadId, int blockSize) {
        this.file = file;
        this.downloadUrl = downloadUrl;
        this.threadId = threadId;
        this.blockSize = blockSize;
    }
 
 
    @Override
    public void run() {
        super.run();
        BufferedInputStream  bis=null;
 
        RandomAccessFile raf=null;
 
 
 
        try {
            HttpURLConnection conn = (HttpURLConnection) downloadUrl.openConnection();
            conn.setAllowUserInteraction(true);
//         開始的位置
            int  startpos=blockSize*(threadId-1);
            int endpos=blockSize*threadId-1;
//            設置當前線程下載的開始點和結束點
            conn.setRequestProperty("Range","bytes="+startpos+"-"+endpos);
            byte[] buffer=new byte[1024];
            bis=new BufferedInputStream(conn.getInputStream());
            raf=new RandomAccessFile(file,"rwd");
            raf.seek(startpos);
            int len=0;
            while((len=bis.read(buffer,0,1024))!=-1){
                raf.write(buffer,0,len);
                downloadlenght+=len;
            }
            isCompleted=true;
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
//每個線程下載的數據長度
    public int getDownloadlenght() {
        return downloadlenght;
    }
//返回線程是否下載完成
    public boolean isCompleted() {
        return isCompleted;
    }
}

FileDownloadThread類

class FileDownloadThread extends Thread {
    /**
     *  文件保存路徑 
     */
    private File file;
    /**
     *  文件下載路徑 (文件網址)
     */
    private URL downloadUrl;
    /**
     *  當前下載線程ID 
     */
    private int threadId;
    /**
     *  線程下載數據長度 
     */
    private int blockSize;
    private int downloadlenght;
    private boolean isCompleted;
 
    public FileDownloadThread(File file, URL downloadUrl, int threadId, int blockSize) {
        this.file = file;
        this.downloadUrl = downloadUrl;
        this.threadId = threadId;
        this.blockSize = blockSize;
    }
 
 
    @Override
    public void run() {
        super.run();
        BufferedInputStream  bis=null;
 
        RandomAccessFile raf=null;
 
 
 
        try {
            HttpURLConnection conn = (HttpURLConnection) downloadUrl.openConnection();
            conn.setAllowUserInteraction(true);
//         開始的位置
            int  startpos=blockSize*(threadId-1);
            int endpos=blockSize*threadId-1;
//            設置當前線程下載的開始點和結束點
            conn.setRequestProperty("Range","bytes="+startpos+"-"+endpos);
            byte[] buffer=new byte[1024];
            bis=new BufferedInputStream(conn.getInputStream());
            raf=new RandomAccessFile(file,"rwd");
            raf.seek(startpos);
            int len=0;
            while((len=bis.read(buffer,0,1024))!=-1){
                raf.write(buffer,0,len);
                downloadlenght+=len;
            }
            isCompleted=true;
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
//每個線程下載的數據長度
    public int getDownloadlenght() {
        return downloadlenght;
    }
//返回線程是否下載完成
    public boolean isCompleted() {
        return isCompleted;
    }
}

詳細配置信息可以參考我寫的這篇文章:http://blog.ncmem.com/wordpress/2019/08/28/net%e6%96%87%e4%bb%b6%e6%89%b9%e9%87%8f%e4%b8%8b%e8%bd%bd/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM