zoukankan      html  css  js  c++  java
  • android --多线程下载

    多线程下载文件的过程是: 

      (1)首先获得下载文件的长度,然后设置本地文件的长度。

          HttpURLConnection.getContentLength();//获取下载文件的长度

         RandomAccessFile file = new RandomAccessFile("QQSetup.exe","rwd");

           file.setLength(filesize);//设置本地文件的长度

     

      (2)依据文件长度和线程数计算每条线程下载的数据长度和下载位置。

          如:文件的长度为6M,线程数为3,那么。每条线程下载的数据长度为2M,每条线程開始下载的位置例如以下图所看到的。

      

       比如10M大小,使用3个线程来下载,

            线程下载的数据长度   (10%3 == 0 ? 10/3:10/3+1) ,第1,2个线程下载长度是4M,第三个线程下载长度为2M

             下载開始位置:线程id*每条线程下载的数据长度 = ?

            下载结束位置:(线程id+1)*每条线程下载的数据长度-1=?

     

      (3)使用HttpRange头字段指定每条线程从文件的什么位置開始下载,下载到什么位置为止,

             如:指定从文件的2M位置開始下载。下载到位置(4M-1byte)为止

               代码例如以下:HttpURLConnection.setRequestProperty("Range", "bytes=2097152-4194303");

     

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

    RandomAccessFile threadfile = new RandomAccessFile("QQWubiSetup.exe ","rwd");

    threadfile.seek(2097152);//从文件的什么位置開始写入数据

    /** 
     *多线程下载,UI更新类  
     *@author young 
     * */  
    public class MultiThreadDownload extends Thread{  
        private static final String TAG = "MultiThreadDownload";  
        /**每个线程须要下载的大小 */  
        private int blockSize;  
        /*** 线程数量<br> 默觉得5个线程下载*/  
        private int threadNum = 5;  
        /*** 文件大小 */  
        private int fileSize;  
        /** * 已经下载多少 */  
        private int downloadSize;  
        /**文件的url,线程编号。文件名*/  
        private String UrlStr,ThreadNo,fileName;  
        /***保存的路径*/  
        private String savePath;  
        /**下载的百分比*/  
        private int downloadPercent = 0;  
        /**下载的 平均速度*/  
        private int downloadSpeed = 0;  
        /**下载用的时间*/  
        private int usedTime = 0;  
        /**当前时间*/  
        private long curTime;  
        /**是否已经下载完毕*/  
        private boolean completed = false;  
        private Handler handler ;  
        /** 
         * 下载的构造函数   
         * @param url  请求下载的URL 
         * @param handler   UI更新使用 
         * @param savePath  保存文件的路径 
         */  
        public MultiThreadDownload(Handler handler,String url,String savePath)  
        {  
            this.handler = handler;  
            this.UrlStr = url;  
            this.savePath = savePath;  
            Log.e(TAG, toString());  
        }  
          
        @Override  
        public void run() {  
              
            FileDownloadThread[] fds = new FileDownloadThread[threadNum];//设置线程数量  
            try {  
                URL url = new URL(UrlStr);  
                URLConnection conn = url.openConnection();  
                fileSize = conn.getContentLength();  
                  
                this.fileName = FileUtil.getFileName(UrlStr);  
                //仅仅创建一个文件,saveFile下载内容  
                File saveFile = new File(savePath+"/"+fileName);  
                Log.e(TAG, "文件一共:"+fileSize+" savePath "+savePath+"  fileName  "+fileName);  
                  
                RandomAccessFile accessFile = new RandomAccessFile(saveFile,"rwd");  
                //设置本地文件的长度和下载文件同样     
                accessFile.setLength(fileSize);    
                accessFile.close();  
                //Handler更新UI,发送消息  
                sendMsg(FileUtil.startDownloadMeg);  
                //每块线程下载数据  
                blockSize = ((fileSize%threadNum)==0)?(fileSize/threadNum):(fileSize/threadNum+1);  
                Log.e(TAG, "每个线程分别下载 :"+blockSize);  
                  
                for (int i = 0; i < threadNum; i++) {  
                    int curThreadEndPosition = (i+1)!=threadNum ?

    ((i+1)*blockSize-1) : fileSize; FileDownloadThread fdt = new FileDownloadThread(url, saveFile, i*blockSize, curThreadEndPosition); fdt.setName("thread"+i); fdt.start(); fds[i]=fdt; } /** * 获取数据,更新UI,直到全部下载线程都下载完毕。 */ boolean finished = false; //開始时间,放在循环外,求解的usedTime就是总时间 long startTime = System.currentTimeMillis(); while(!finished) { downloadSize = 0; finished = true; for (int i = 0; i < fds.length; i++) { downloadSize+= fds[i].getDownloadSize(); if(!fds[i].isFinished()) { finished = false; } } downloadPercent = (downloadSize*100)/fileSize; curTime = System.currentTimeMillis(); System.out.println("curTime = "+curTime+" downloadSize = "+downloadSize+" usedTime "+(int) ((curTime-startTime)/1000)); usedTime = (int) ((curTime-startTime)/1000); if(usedTime==0)usedTime = 1; downloadSpeed = (downloadSize/usedTime)/1024; sleep(1000);/*1秒钟刷新一次界面*/ sendMsg(FileUtil.updateDownloadMeg); } Log.e(TAG, "下载完毕"); completed = true; sendMsg(FileUtil.endDownloadMeg); } catch (Exception e) { Log.e(TAG, "multi file error Exception "+e.getMessage()); e.printStackTrace(); } super.run(); } /** * 得到文件的大小 * @return */ public int getFileSize() { return this.fileSize; } /** * 得到已经下载的数量 * @return */ public int getDownloadSize() { return this.downloadSize; } /** * 获取下载百分比 * @return */ public int getDownloadPercent(){ return this.downloadPercent; } /** * 获取下载速度 * @return */ public int getDownloadSpeed(){ return this.downloadSpeed; } /** * 改动默认线程数 * @param threadNum */ public void setThreadNum(int threadNum){ this.threadNum = threadNum; } /** * 分块下载完毕的标志 * @return */ public boolean isCompleted(){ return this.completed; } @Override public String toString() { return "MultiThreadDownload [threadNum=" + threadNum + ", fileSize=" + fileSize + ", UrlStr=" + UrlStr + ", ThreadNo=" + ThreadNo + ", savePath=" + savePath + "]"; } /** * 发送消息。用户提示 * */ private void sendMsg(int what) { Message msg = new Message(); msg.what = what; handler.sendMessage(msg); }

    public class FileDownloadThread extends Thread{  
        private static final String TAG = "FileDownloadThread";  
        /**缓冲区 */  
        private static final int BUFF_SIZE = 1024;  
        /**须要下载的URL*/  
        private URL url;  
        /**缓存的FIle*/  
        private File file;  
        /**開始位置*/  
        private int startPosition;  
        /**结束位置*/  
        private int endPosition;  
        /**当前位置*/  
        private int curPosition;  
        /**完毕*/  
        private boolean finished = false;  
        /**已经下载多少*/  
        private int downloadSize = 0;  
          
        /*** 
         * 分块文件下载,能够创建多线程模式 
         * @param url   下载的URL 
         * @param file  下载的文件 
         * @param startPosition 開始位置 
         * @param endPosition   结束位置 
         */  
        public FileDownloadThread(URL url, File file, int startPosition,  
                int endPosition) {  
            this.url = url;  
            this.file = file;  
            this.startPosition = startPosition;  
            this.curPosition = startPosition;  
            this.endPosition = endPosition;  
            Log.e(TAG, toString());  
        }  
          
        @Override  
        public void run() {  
            BufferedInputStream bis = null;  
            RandomAccessFile rAccessFile = null;  
            byte[] buf = new byte[BUFF_SIZE];  
            URLConnection conn = null;  
            try {  
                conn = url.openConnection();  
                conn.setConnectTimeout(10000);//设置超时  
                conn.setReadTimeout(10000);  
                conn.setAllowUserInteraction(true);  
                        System.out.println(this.getName()+" startPosition "+startPosition+" endPosition "+endPosition);  
                        conn.setRequestProperty("Range", "bytes="+(startPosition)+"-"+endPosition);  //取剩余未下载的  
                        rAccessFile = new RandomAccessFile(file,"rwd");//读写  
                         //设置从什么位置開始写入数据   
                        rAccessFile.seek(startPosition);  
                        bis = new BufferedInputStream(conn.getInputStream(), BUFF_SIZE);  
                        while(curPosition<endPosition)  //当前位置小于结束位置  继续下载  
                        {  
                            int len = bis.read(buf,0,BUFF_SIZE);  
                            if(len==-1)   //下载完毕    
                            {   
                                break;  
                            }  
                            rAccessFile.write(buf,0,len);  
                            curPosition = curPosition +len;  
                            if(curPosition > endPosition)  
                            {   //假设下载多了。则减去多余部分  
                                System.out.println("  curPosition > endPosition  !!!!");  
                                int extraLen = curPosition-endPosition;  
                                downloadSize += (len-extraLen+1);  
                            }else{  
                                downloadSize+=len;  
                            }  
                        }  
                        this.finished = true;  //当前阶段下载完毕  
                Log.e(TAG, "当前"+this.getName()+"下载完毕");  
            } catch (Exception e) {  
                Log.e(TAG, "download error Exception "+e.getMessage());  
                e.printStackTrace();  
            }finally{  
                //关闭流  
                FileUtil.closeInputStream(bis);  
                try {  
                    rAccessFile.close();  
                } catch (IOException e) {  
                    // TODO Auto-generated catch block  
                    Log.e("AccessFile", "AccessFile IOException "+e.getMessage());  
                }  
            }  
            super.run();  
        }  
          
        /** 
         * 是否完毕当前段下载完毕 
         * @return 
         */  
        public boolean isFinished() {  
            return finished;  
        }  
        /** 
         * 已经下载多少 
         * @return 
         */  
        public int getDownloadSize() {  
            return downloadSize;  
        }  
      
        @Override  
        public String toString() {  
            return "FileDownloadThread [url=" + url + ", file=" + file  
                    + ", startPosition=" + startPosition + ", endPosition="  
                    + endPosition + ", curPosition=" + curPosition + ", finished="  
                    + finished + ", downloadSize=" + downloadSize + "]";  
        }  
    

    多线程下载是分段下载,创建保存一个文件,子线程分别通过RandomAccessFile类进行写入操作。


    演示样例源代码:demo下载

  • 相关阅读:
    c语言结构体数组引用
    c语言结构体数组定义的三种方式
    如何为SAP WebIDE开发扩展(Extension),并部署到SAP云平台上
    SAP SRM ABAP Webdynpro和CFCA usb key集成的一个原型开发
    使用SAP API portal进行SAP SuccessFactors的API测试
    SAP UI5应用里的页面路由处理
    在SAP WebIDE Database Explorer里操作hdi实例
    如何使用SAP事务码SAT进行UI应用的性能分析
    使用SAP WebIDE进行SAP Cloud Platform Business Application开发
    SAP CRM WebClient UI ON_NEW_FOCUS的用途
  • 原文地址:https://www.cnblogs.com/yxysuanfa/p/7255649.html
Copyright © 2011-2022 走看看