天天看點

Android 檔案下載下傳--普通多線程下載下傳

我們都知道使用多線程下載下傳檔案可以更快地完成檔案的下載下傳,但是為什麼呢?

答:因為搶占的伺服器資源多,假設伺服器最多服務100個使用者,伺服器中的一個線程 對應一個使用者100條線程在計算機中并發執行,由CPU劃分時間片輪流執行,加入a有99條線程 下載下傳檔案,那麼相當于占用了99個使用者資源,自然就有用較快的下載下傳速度

PS:當然不是線程越多就越好,開啟過多線程的話,app需要維護和同步每條線程的開銷, 這些開銷反而會導緻下載下傳速度的降低,另外還和你的網速有關!

多線程下載下傳的流程:

  1. 擷取網絡連接配接
  2. 本地磁盤建立相同大小的空檔案
  3. 計算每條線程需從檔案哪個部分開始下載下傳,結束
  4. 依次建立,啟動多條線程來下載下傳網絡資源的指定部分
Android 檔案下載下傳--普通多線程下載下傳

PS:這裡直接建立一個Java項目,然後在JUnit裡運作指定方法即可

核心代碼如下:

public class Downloader {
    // 添加@Test标記是表示該方法是Junit測試的方法,就可以直接運作該方法了
    @Test
    public void download() throws Exception {
        // 設定URL的位址和下載下傳後的檔案名
        String filename = "meitu.exe";
        String path = "http://10.13.20.32:8080/Test/XiuXiu_Green.exe";
        URL url = new URL(path);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setConnectTimeout();
        conn.setRequestMethod("GET");
        // 獲得需要下載下傳的檔案的長度(大小)
        int filelength = conn.getContentLength();
        System.out.println("要下載下傳的檔案長度" + filelength);
        // 生成一個大小相同的本地檔案
        RandomAccessFile file = new RandomAccessFile(filename, "rwd");
        file.setLength(filelength);
        file.close();
        conn.disconnect();
        // 設定有多少條線程下載下傳
        int threadsize = ;
        // 計算每個線程下載下傳的量
        int threadlength = filelength %  ==  ? filelength /  : filelength + ;
        for (int i = ; i < threadsize; i++) {
            // 設定每條線程從哪個位置開始下載下傳
            int startposition = i * threadlength;
            // 從檔案的什麼位置開始寫入資料
            RandomAccessFile threadfile = new RandomAccessFile(filename, "rwd");
            threadfile.seek(startposition);
            // 啟動三條線程分别從startposition位置開始下載下傳檔案
            new DownLoadThread(i, startposition, threadfile, threadlength, path).start();
        }
        int quit = System.in.read();
        while ('q' != quit) {
            Thread.sleep();
        }
    }

    private class DownLoadThread extends Thread {
        private int threadid;
        private int startposition;
        private RandomAccessFile threadfile;
        private int threadlength;
        private String path;

        public DownLoadThread(int threadid, int startposition, RandomAccessFile threadfile, int threadlength, String path) {
            this.threadid = threadid;
            this.startposition = startposition;
            this.threadfile = threadfile;
            this.threadlength = threadlength;
            this.path = path;
        }

        public DownLoadThread() {
        }

        @Override
        public void run() {
            try {
                URL url = new URL(path);
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                conn.setConnectTimeout();
                conn.setRequestMethod("GET");
                // 指定從什麼位置開始下載下傳
                conn.setRequestProperty("Range", "bytes=" + startposition + "-");
                // System.out.println(conn.getResponseCode());
                if (conn.getResponseCode() == ) {
                    InputStream is = conn.getInputStream();
                    byte[] buffer = new byte[];
                    int len = -;
                    int length = ;
                    while (length < threadlength && (len = is.read(buffer)) != -) {
                        threadfile.write(buffer, , len);
                        // 計算累計下載下傳的長度
                        length += len;
                    }
                    threadfile.close();
                    is.close();
                    System.out.println("線程" + (threadid + ) + "已下載下傳完成");
                }
            } catch (Exception ex) {
                System.out.println("線程" + (threadid + ) + "下載下傳出錯" + ex);
            }
        }

    }
}
           

注意事項:

  • int filelength = conn.getContentLength(); //獲得下載下傳檔案的長度(大小)
  • RandomAccessFile file = new RandomAccessFile(filename, “rwd”);//該類運作對檔案進行讀寫,是多線程下載下傳的核心
  • nt threadlength = filelength % 3 == 0 ? filelength/3:filelength+1;//計算每個線程要下載下傳的量
  • conn.setRequestProperty(“Range”, “bytes=”+startposition+”-“);//指定從哪個位置開始讀寫,這個是URLConnection提供的方法
  • //System.out.println(conn.getResponseCode());

    //這個注釋了的代碼是用來檢視conn的傳回碼的,我們前面用的都是200,而針對多線程的話,通常是206,必要時我們可以通過調用該方法檢視傳回碼!

  • int quit = System.in.read();while(‘q’ != quit){Thread.sleep(2000);}

    //這段代碼是做延時操作的,因為我們用的是本地下載下傳,可能該方法運作完了,而我們的線程還沒有開啟,這樣會引發異常,這裡的話,讓使用者輸入一個字元,如果是’q’的話就退出