java 多线程断点下载功能

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;


public class Demo {
    
    //线程个数
    public static int threadCount = 3;
    
    //线程下载完成的个数
    public static int finishedCount = 3;
    /**
     * 多线程下载测试类
     * @param args
     * @throws Exception 
     */
    public static void main(String[] args) throws Exception {
        
        //1、连接服务器,获取一个文件,获取文件的长度,在本地创建一个大小跟服务器文件一样大的临时文件
        String path = "http://192.168.1.100:8080/test.avi";
        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();
            System.out.println("文件总长度:"+length);
            
            //在客服端创建出来一个大小跟服务器端文件一样大小的临时文件
            RandomAccessFile raf = new RandomAccessFile("test.avi", "rwd");
            //指定创建的这个文件的长度
            raf.setLength(length);
            raf.close();
            
            
            //假设是3个线程去下载资源
            //平均每一个线程下载的文件的大小
            int blockSize = length / threadCount;
            for(int threadId=1;threadId<=threadCount;threadId++)
            {
                //线程下载的开始位置
                int startIndex = (threadId-1)*blockSize;
                int endIndex = threadId*blockSize;
                if(threadId==threadCount)
                {
                    endIndex = length;
                    
                }
                System.out.println("线程:"+threadId+" 下载:---"+startIndex+"--->"+endIndex);
                
                //启动线程
                new DownloadThread(threadId,startIndex,endIndex,path).start();
            }
            
        }
        else
        {
            System.out.println("服务器错误");
        }
    
    
    }
    
    public static class DownloadThread extends Thread
    {
        private int threadId;  //线程id
        private int startIndex; 
        private int endIndex;
        private String path;
        
        public DownloadThread(int threadId, int startIndex, int endIndex,
                String path) {
            super();
            this.threadId = threadId;
            this.startIndex = startIndex;
            this.endIndex = endIndex;
            this.path = path;
        }

        public void run() {
            try {
                
                //检查是否存在记录文件下载长度的文件,如果存在读取这个文件的数据
                
                File tempFile = new File(threadId+".txt");
                if(tempFile.exists() && tempFile.length() >0)
                {
                    FileInputStream fis = new FileInputStream(tempFile);
                    byte[] temp = new byte[1024];
                    int leng = fis.read(temp);
                    String downloadLen = new String(temp,0,leng);
                    int downloadLenInt = Integer.parseInt(downloadLen);
                    startIndex = downloadLenInt;
                    fis.close();
                }
                
                System.out.println("线程:"+threadId+"实际下载:---"+startIndex+"--->"+endIndex);
                
                URL url = new URL(path);
                HttpURLConnection conn =(HttpURLConnection) url.openConnection();
                conn.setConnectTimeout(5000);
                conn.setRequestMethod("GET");
                
                //重要 : 请求服务器下载部分的文件指定文件的位置
                conn.setRequestProperty("Range", "bytes="+startIndex+"-"+endIndex);
                
                //从服务器请求全部资源 200 ok 如果从服务器请求部分资源 206 ok
                int code = conn.getResponseCode();
                System.out.println("code:"+code);
                
                //已经设置了请求的位置 返回的事当前位置对应的文件的输入流
                InputStream is = conn.getInputStream();
                
                //在客服端创建出来一个大小跟服务器端文件一样大小的临时文件
                RandomAccessFile raf = new RandomAccessFile("test.avi", "rwd");
                //随机写文件的时候从哪个位置开始
                raf.seek(startIndex); //定位文件
                
                int len = 0;
                byte[] buffer = new byte[1024];
                int total = 0;
                while((len=is.read(buffer))!=-1)
                {
                    //记录已经下载完成的长度
                    RandomAccessFile recordFile = new RandomAccessFile(threadId+".txt","rwd");
                    raf.write(buffer,0,len);
                    //下载完成的长度
                    total += len;
                    recordFile.write((total+startIndex +"").getBytes());
                    recordFile.close();
                    
                }
                
                is.close();
                raf.close();
                
                System.out.println("线程:"+threadId+"下载完毕了。。。");
                
            } catch (Exception e) {
                e.printStackTrace();
            }finally
            {
                //用于删除各个线程记录已经下载完成的长度的文件
                finishedCount--;
                //所有线程下载完成
                if(finishedCount==0)
                {
                    
                    for(int i=1;i<=threadCount;i++)
                    {
                        //删除记录文件
                        File deleteFile = new File(i+".txt");
                        deleteFile.delete();
                    }
                    
                }
                
            }
        }
        
        
    }

}
原文地址:https://www.cnblogs.com/zoro-zero/p/3955015.html