美文网首页
2018-03-10 android多线程断点下载实现

2018-03-10 android多线程断点下载实现

作者: 紫杉叶子 | 来源:发表于2018-03-12 10:46 被阅读0次
    笔记如下
    • 什么是多线程下载?


      图二 多线程下载的分析.jpg
    • 首先要获得要下载文件的总大小并创建规定大小的空文件
                    //拿到文件的大小
                    int length = conn.getContentLength();
                    
                    //getPathName(path)是得到文件名称
                    File file = new File(getPathName(path));
                    
                    //首先创建规定大小的空文件
                    RandomAccessFile raf = new RandomAccessFile(file, "rw");
                    
                    raf.setLength(length);
                    
                    raf.close();
    
    • 每条线程的下载的起始位置于结束位置公式
                    //去启动线程去下载文件
                    //threadId :线程的id号
                    //threadCount :开几条线程----3条
                    for (int threadId = 0; threadId < threadCount; threadId++) {
                        
                        int startIndex = threadId*blockSize;
                        int endIndex  = (threadId+1)*blockSize-1;
                        
                        if (threadId==(threadCount-1)) {
                            endIndex = length-1;
                        }
                        
                        
                        
                        //System.out.println("第"+threadId+"线程:下载 从"+startIndex +"~"+endIndex);
                        
                        //开启线程下载
                        new DownloadFilePartThread(threadId, startIndex, endIndex).start();
                        
                    }
    
    
    • 通过请求头告诉服务器要下载的内容
    conn.setRequestProperty("range", "bytes=" +startIndex+"-"+endIndex);
    
    
    • 将服务器传回的数据写到文件中
                        //拿到数据
                        InputStream in = conn.getInputStream();
                                        
                        //告诉从哪个位子开始写
                        //raf.seek(startIndex);
                        
                        int len=0;
                        byte[] buf = new byte[1024];
                        while ((len=in.read(buf))>0) {
                            raf.write(buf,0,len);
                            
                            //将实时的位置记录下来,方便下面紧接着去往文件中去写
                            currentPostion=currentPostion+len;
                            //实现断点下载
                            File info  = new File(threadId+".position");
                            
                            OutputStream out = new FileOutputStream(info);
                            
                            //以字符串的值记录当前缓存的配置
                            //out.write(String.valueOf(currentPostion).getBytes());
                            out.write((currentPostion+"").getBytes());
                            out.close();
                            
                        }
    
    • 实现断点下载
      断点下载就是记录上次下载停止的地方,设置为开始地方继续下载------将停止地点记录到文件中.
                            //将实时的位置记录下来,方便下面紧接着去往文件中去写
                            currentPostion=currentPostion+len;
                            //实现断点下载
                            File info  = new File(threadId+".position");
                            
                            OutputStream out = new FileOutputStream(info);
                            
                            //以字符串的值记录当前缓存的配置
                            //out.write(String.valueOf(currentPostion).getBytes());
                            out.write((currentPostion+"").getBytes());
                            out.close();
    
    
                    //读取之前已经下载的地方,继续下载
                    File ilf  = new File(threadId+".position");
                    
                    if (ilf.exists() && ilf.length()>0) {
                        
                        BufferedReader br = new BufferedReader(new FileReader(ilf));
                        String vl = br.readLine();
                        
                        int alreadyWritePosition  = Integer.valueOf(vl);
                        //重新设置http请求头,设置起始下载位置
                        conn.setRequestProperty("range", "bytes=" +alreadyWritePosition+"-"+endIndex);
                        //告诉从哪个位子开始写
                        raf.seek(alreadyWritePosition);
                        
                        System.out.println("表示之前下载过");
                        
                    }else{
                        
                        conn.setRequestProperty("range", "bytes=" +startIndex+"-"+endIndex);
                        //告诉从哪个位子开始写
                        raf.seek(startIndex);
                        System.out.println("表示之前没有下载过");
                    }
    
    • 文件下载完成后,还要删除记录位置的文件
    synchronized (NultiThreadDownload.class) {
    
                        currentRunningThread--;
                        if (currentRunningThread <= 0) {
    
                            // 将记录下载位置的文件给删掉
    
                            for (threadId = 0; threadId < threadCount; threadId++) {
                                File fff = new File(threadId + ".position");
                                
                                fff.renameTo(new File(threadId + ".position.finish"));
                                File fll = new File(threadId + ".position.finish");
                                fll.delete();
                            }
                        }
                    }
    
    • 全部源码
    public class MultiThreadDownload {
        
        //规定用三条线程去下载
        private  static int  threadCount = 3;
        
        //线程计数器
        private static int currentRunningThread = 3;
        
        //private static String path="http://169.254.210.207:8080/file.txt";
        private static String path="http://169.254.210.207:8080/ff.exe";
        public static void main(String[] args){
            
            //1.向服务器发请求,拿到要下载的文件的长度是多少
            
            try {
                URL url = new URL(path);
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                
                conn.setConnectTimeout(5000);
                conn.setRequestMethod("GET");
                
                int code = conn.getResponseCode();
                
                if (code == 200) {
                    
                    //拿到文件的大小
                    int length = conn.getContentLength();
                    
                    //getPathName(path)是得到文件名称
                    //得到文件路径
                    File file = new File(getPathName(path));
                    
                    //首先创建规定大小的空文件
                    RandomAccessFile raf = new RandomAccessFile(file, "rw");
                    
                    raf.setLength(length);
                    
                    raf.close();
                    
                    //每块线程下载的平均大小
                    int blockSize = length/threadCount;
                    
                    
                    
                    //去启动线程去下载文件
                    //threadId :线程的id号
                    //threadCount :开几条线程----3条
                    for (int threadId = 0; threadId < threadCount; threadId++) {
                        
                        int startIndex = threadId*blockSize;
                        int endIndex  = (threadId+1)*blockSize-1;
                        
                        if (threadId==(threadCount-1)) {
                            endIndex = length-1;
                        }
                        
                        
                        
                        //System.out.println("第"+threadId+"线程:下载 从"+startIndex +"~"+endIndex);
                        
                        
                        new DownloadFilePartThread(threadId, startIndex, endIndex).start();
                        
                    }
                    
                    
                }
                
                
                
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            
            
            
            
        }
        
        
        
        
        private static class DownloadFilePartThread extends Thread{
            
            //线程的id号
            private int threadId;
            
            //线程的开始位置
            private int startIndex;
            
            //线程的结束位置
            private int endIndex;
            
            //当前线程下载位置
            private int currentPostion;
            
            
            
            public DownloadFilePartThread(int threadId,int startIndex,int endIndex){
                this.threadId  = threadId;
                this.startIndex  = startIndex;
                this.endIndex  = endIndex;
                currentPostion = startIndex;
            }
            
            @Override
            public void run() {
                // TODO Auto-generated method stub
    
                //干下载耗时的事
                System.out.println("第"+threadId+"线程:开始下载了.....   从"+startIndex +"~"+endIndex);
                
                
                try {
                    URL url = new URL(path);
                    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                    
                    conn.setConnectTimeout(5000);
                    conn.setRequestMethod("GET");
                    
                    //在多线程下载中只需要目标文件的一部分的数据
                    //需要告诉服务器,要下载的内容
                    //需要设置http请求头可以实现
                    
                    //startIndex ~ endIndex
                    
                    conn.setRequestProperty("range", "bytes=" +startIndex+"-"+endIndex);
                    
                    File file = new File(getPathName(path));
                    
                    RandomAccessFile raf = new RandomAccessFile(file, "rw");
                    
                    //读取之前已经下载的地方,继续下载
                    File ilf  = new File(threadId+".position");
                    
                    if (ilf.exists() && ilf.length()>0) {
                        
                        BufferedReader br = new BufferedReader(new FileReader(ilf));
                        String vl = br.readLine();
                        
                        int alreadyWritePosition  = Integer.valueOf(vl);
                        //重新设置http请求头,设置起始下载位置
                        conn.setRequestProperty("range", "bytes=" +alreadyWritePosition+"-"+endIndex);
                        //告诉从哪个位子开始写
                        raf.seek(alreadyWritePosition);
                        
                        System.out.println("表示之前下载过");
                        
                    }else{
                        
                        conn.setRequestProperty("range", "bytes=" +startIndex+"-"+endIndex);
                        //告诉从哪个位子开始写
                        raf.seek(startIndex);
                        System.out.println("表示之前没有下载过");
                    }
                    
                    
                    
                    //多线程下载返回----206
                    int code = conn.getResponseCode();
                    if (code == 206) {
                        
                        //拿到数据
                        InputStream in = conn.getInputStream();
                                        
                        //告诉从哪个位子开始写
                        //raf.seek(startIndex);
                        
                        int len=0;
                        byte[] buf = new byte[1024];
                        while ((len=in.read(buf))>0) {
                            raf.write(buf,0,len);
                            
                            //将实时的位置记录下来,方便下面紧接着去往文件中去写
                            currentPostion=currentPostion+len;
                            //实现断点下载
                            File info  = new File(threadId+".position");
                            
                            OutputStream out = new FileOutputStream(info);
                            
                            //以字符串的值记录当前缓存的配置
                            //out.write(String.valueOf(currentPostion).getBytes());
                            out.write((currentPostion+"").getBytes());
                            out.close();
                            
                        }
                        
                        
                        
                        in.close();
                        raf.close();
                    }
                    
                    System.out.println("第"+threadId+"线程:下载结束了..... ");
                    
                    //等到线程完成后再去删文件
                    //弄一个计数器,记住总共有多少线程下载,每当一个线程下载后就-1
                    //当计数器小于0或等于0的时候,就说明没有线程在下载了,就删除记录下位置的文件
                    
                    synchronized (MultiThreadDownload.class) {
    
                        currentRunningThread--;
                        if (currentRunningThread <= 0) {
    
                            // 将记录下载位置的文件给删掉
    
                            for (threadId = 0; threadId < threadCount; threadId++) {
                                File fff = new File(threadId + ".position");
                                
                                fff.renameTo(new File(threadId + ".position.finish"));
                                File fll = new File(threadId + ".position.finish");
                                fll.delete();
                            }
                        }
                    }
                    
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                
                
                
            }
            
        }
        
        
        public static String getPathName(String path){
            
            int index = path.lastIndexOf("/");
            
            return path.substring(index+1);
            
            
        }
    
    }
    

    相关文章

      网友评论

          本文标题:2018-03-10 android多线程断点下载实现

          本文链接:https://www.haomeiwen.com/subject/txvvfftx.html