【Java】之 写个线程下载文件(支持断点续传)

来源:互联网 发布:情定三生向天和知夏 编辑:程序博客网 时间:2024/06/05 17:16

持续更新。。。

本文分三次完成。


Step 1

实现功能:

  实现基本下载,参数封装。

学习方面:

  IO,URL, URLConnection, HTTPsConnection

public class DownUtils {    private final String url;       private final String fileName;    private final String targetDir;    public DownUtils(String url, String fileName, String targetDir){        this.url = url;        this.fileName = fileName;        this.targetDir = targetDir;    }    public DownUtils(String url,String fileName){        this.url = url;        this.fileName = fileName;        this.targetDir = "";    }    public void makeSureDir(){        File targetDir = new File(this.targetDir);        if(!targetDir.exists())            targetDir.mkdir();    }    public String getFileName(){        if (!"".equals(targetDir)){            makeSureDir();            return targetDir + File.separator + fileName;        }        return fileName;    }    public void down(){        try(            RandomAccessFile raf = new RandomAccessFile(getFileName(), "rw")        )        {            URL url = new URL(this.url);            HttpURLConnection connection = (HttpURLConnection)url.openConnection();            connection.setConnectTimeout(8000);            connection.setRequestMethod("GET");            //防止屏蔽程序抓取而返回403错误            connection.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");            connection.setRequestProperty("Accept",                "image/gif, image/jpeg, image/pjpeg, image/pjpeg, "                    + "application/x-shockwave-flash, application/xaml+xml, "                    + "application/vnd.ms-xpsdocument, application/x-ms-xbap, "                    + "application/x-ms-application, application/vnd.ms-excel, "                    + "application/vnd.ms-powerpoint, application/msword, */*");            connection.setRequestProperty("Accept-Language", "zh-CN");            connection.setRequestProperty("Charset", "UTF-8");            InputStream inputStream = connection.getInputStream();            byte[] buffer = new byte[1024];            int hasRead = 0;            while((hasRead = inputStream.read(buffer)) > 0){                raf.write(buffer, 0, hasRead);            }            System.out.println("info:" + url + " download success");        }        catch (IOException e){            e.printStackTrace();        }    }    public static void main(String[] args) {        DownUtils downUtils = new DownUtils("http://101.95.48.97:8005/res/upload/interface/apptutorials/manualstypeico/6f83ce8f-0da5-49b3-bac8-fd5fc67d2725.png"            , "yyf.png", "C:\\Users\\donal\\Desktop\\tools");        downUtils.down();    }}

Step 2

实现功能:

  多线程下载

学习方面:

  thread

思想:按线程数将一个文件分成若干份,每个线程执行其中的一份。

package cn.Down;/** * Created by donal on 2017/2/21. */import java.io.*;import java.net.HttpURLConnection;import java.net.URL;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;/** *  实现多线程下载文件,支持断点续传 * *  1.多线程 *  2.下载:IO流 *  3.断点续传:RandomAccessFile *  4.下载:URL * *  step1: 实现文件下载 *  (step1,2 同时实现代码封装、整洁) *  step2: 多线程下载 *  step3: 实现断点续传 */public class DownUtils {    private final int fileSize;    private final String url;    private final String fileName;    private final String targetDir;    private final int threadSize;    private final ExecutorService executorService;    public DownUtils(String url, String fileName, String targetDir, int threadSize){        this.url = url;        this.fileName = fileName;        this.targetDir = targetDir;        this.threadSize = threadSize;        executorService = Executors.newFixedThreadPool(threadSize);        fileSize = getConnection(url).getContentLength();    }    public DownUtils(String url,String fileName, int threadSize){        this.url = url;        this.fileName = fileName;        this.threadSize = threadSize;        this.targetDir = "";        executorService = Executors.newFixedThreadPool(threadSize);        fileSize = getConnection(url).getContentLength();    }    public DownUtils(String url, String fileName){        this.url = url;        this.fileName = fileName;        this.targetDir = "";        this.threadSize = 1;        executorService = Executors.newFixedThreadPool(threadSize);        fileSize = getConnection(url).getContentLength();    }    public void makeSureDir(){        File targetDir = new File(this.targetDir);        if(!targetDir.exists())            targetDir.mkdir();    }    public String getFileName(){        if (!"".equals(targetDir)){            makeSureDir();            return targetDir + File.separator + fileName;        }        return fileName;    }    public static HttpURLConnection getConnection(String urlPath) {        try {            URL url = new URL(urlPath);            HttpURLConnection connection = (HttpURLConnection)url.openConnection();            connection.setConnectTimeout(8000);            connection.setRequestMethod("GET");            //防止屏蔽程序抓取而返回403错误            connection.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");            connection.setRequestProperty("Accept",                "image/gif, image/jpeg, image/pjpeg, image/pjpeg, "                    + "application/x-shockwave-flash, application/xaml+xml, "                    + "application/vnd.ms-xpsdocument, application/x-ms-xbap, "                    + "application/x-ms-application, application/vnd.ms-excel, "                    + "application/vnd.ms-powerpoint, application/msword, */*");            connection.setRequestProperty("Accept-Language", "zh-CN");            connection.setRequestProperty("Charset", "UTF-8");            return connection;        } catch (IOException e){            e.printStackTrace();            throw new RuntimeException(e);        }    }    public int getFileSize(){        return fileSize;    }    public void download(){        int partFileSize = fileSize / threadSize + 1;        int startPos = 0;        for (int i = 0 ; i < threadSize; ++i){            executorService.execute(new DownThread(i, startPos, partFileSize));            startPos += partFileSize;        }        executorService.shutdown();    }    private class DownThread implements Runnable{        private final int threadId;        private final int startPos;        private final int partFileSize;        public DownThread(int threadId, int startPos, int partFileSize){            this.threadId = threadId;            this.startPos = startPos;            this.partFileSize = partFileSize;        }        public void writePartFile(){            try (                InputStream inputStream = getConnection(url).getInputStream();                RandomAccessFile raf = new RandomAccessFile(getFileName(), "rw")            )            {                byte[] buffer = new byte[1024];                int hasRead;                int length = 0;                inputStream.skip(startPos);                raf.seek(startPos);                while((length < partFileSize) && (hasRead = inputStream.read(buffer)) > 0){                    raf.write(buffer, 0, hasRead);                    length += hasRead;                }            }            catch (IOException e){                e.printStackTrace();            }        }        @Override        public void run(){            System.out.println("#" + threadId + " is loading...");            writePartFile();            System.out.println("#" + threadId + " succeeded!");        }    }}
package cn.Down;/** * Created by donal on 2017/2/23. */public class DownUtilsTest {    public static void main(String[] args) {        DownUtils downUtils = new DownUtils("http://p1.gexing.com/G1/M00/C8/77/rBACJlYnjHzxEOY2AAC9B6vX98g105.jpg"            , "ais.jpg",  5);        downUtils.download();        /*new Thread(new Runnable() {            @Override            public void run() {                while(downUtils.getCompleteRate() <1 ){                    System.out.println("已完成:" + downUtils.getCompleteRate());                    try {                        Thread.sleep(10);                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            }        });*/    }}

Step 3

实现功能:

  实现断点续传(只定义了接口)

学习方面:

  File, IO。

思想:按线程名创建对应的临时文件,若要暂停或者退出,则调用setBreakPoint()函数,对临时文件写入startPos,endPos。

疑惑:如何控制线程(比如控制线程生命周期,即destroy)

结果图:

这里写图片描述

package cn.Down;/** * Created by donal on 2017/2/21. */import java.io.*;import java.net.HttpURLConnection;import java.net.URL;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class DownUtils {    private final long fileSize;    private final int threadSize;    private final String url;    private final String fileName;    private final String targetDir;    private final ExecutorService executorService;    public DownUtils(String url, String fileName, String targetDir, int threadSize){        this.url = url;        this.fileName = fileName;        this.targetDir = targetDir;        this.threadSize = threadSize;        executorService = Executors.newFixedThreadPool(threadSize);        fileSize = getConnection(url).getContentLength();    }    public DownUtils(String url,String fileName, int threadSize){        this.url = url;        this.fileName = fileName;        this.threadSize = threadSize;        this.targetDir = "";        executorService = Executors.newFixedThreadPool(threadSize);        fileSize = getConnection(url).getContentLength();    }    public DownUtils(String url, String fileName){        this.url = url;        this.fileName = fileName;        this.targetDir = "";        this.threadSize = 1;        executorService = Executors.newFixedThreadPool(threadSize);        fileSize = getConnection(url).getContentLength();    }    private void makeSureDir(){        File targetDir = new File(this.targetDir);        if(!targetDir.exists())            targetDir.mkdir();    }    public String getFileName(){        if (!"".equals(targetDir)){            makeSureDir();            return targetDir + File.separator + fileName;        }        return fileName;    }    private static HttpURLConnection getConnection(String urlPath) {        try {            URL url = new URL(urlPath);            HttpURLConnection connection = (HttpURLConnection)url.openConnection();            connection.setConnectTimeout(8000);            connection.setRequestMethod("GET");            //防止屏蔽程序抓取而返回403错误            connection.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");            connection.setRequestProperty("Accept",                "image/gif, image/jpeg, image/pjpeg, image/pjpeg, "                    + "application/x-shockwave-flash, application/xaml+xml, "                    + "application/vnd.ms-xpsdocument, application/x-ms-xbap, "                    + "application/x-ms-application, application/vnd.ms-excel, "                    + "application/vnd.ms-powerpoint, application/msword, */*");            connection.setRequestProperty("Accept-Language", "zh-CN");            connection.setRequestProperty("Charset", "UTF-8");            return connection;        } catch (IOException e){            e.printStackTrace();            throw new RuntimeException("get connection default.");        }    }    private File fileFactory(String fileName){        return new File(fileName);    }    private boolean isFileExist(){        File targetFile = fileFactory(getFileName());        if (targetFile.exists() && targetFile.length() == fileSize){            System.out.println("The file you want to download has existed!!");            return true;        }        return false;    }    private void createThread(){        long partFileSize = fileSize / threadSize + 1;        long startPos = 0;        for (int i = 0 ; i < threadSize; ++i){            executorService.execute(new DownThread(i, startPos, partFileSize));            startPos += partFileSize;        }        executorService.shutdown();    }    public void download(){        if (isFileExist())            return;        System.out.println(url + "    is ready to download.----------");        createThread();    }    private class DownThread implements Runnable{        private long threadId;        private long startPos;        private long endPos;        private long partFileSize;        private final String tempFileName;        private transient File tempFile;        public DownThread(int threadId, long startPos,  long partFileSize) {            this.threadId = threadId;            this.startPos = startPos;            this.partFileSize = partFileSize;            endPos = partFileSize + startPos;            tempFileName = "temp" + threadId + ".txt";        }        public void writePartFile(){            try (                InputStream inputStream = getConnection(url).getInputStream();                RandomAccessFile raf = new RandomAccessFile(getFileName(), "rw")            )            {                byte[] buffer = new byte[1024];                int hasRead;                inputStream.skip(startPos);                raf.seek(startPos);                int length = 0;                while((length < partFileSize) && (hasRead = inputStream.read(buffer)) > 0){                    raf.write(buffer, 0, hasRead);                    startPos += hasRead;                }                tempFile.deleteOnExit();            }            catch (IOException e){                throw new RuntimeException("write part file default.");            }        }        private void readTempFile(){            try(                RandomAccessFile raf = new RandomAccessFile(tempFileName, "rw")            )            {                raf.seek(0);                startPos = raf.readLong();                raf.seek(8);                endPos = raf.readLong();                partFileSize = endPos - startPos;            }            catch (IOException e){                throw new RuntimeException("read from temp file default.");            }        }        private void createTempFile() {            try {                tempFile = File.createTempFile(tempFileName, null);            } catch (IOException e) {                throw new RuntimeException("create new file default.");            }        }        public void makeSureTempFileExist() {            tempFile = new File(tempFileName);            if (tempFile.exists()){                readTempFile();            }else {                createTempFile();            }        }        private void setBreakPoint(){            try(                RandomAccessFile raf = new RandomAccessFile(tempFileName, "rw")                )            {                raf.writeLong(startPos);                raf.writeLong(endPos);            }            catch (IOException e){                e.printStackTrace();                throw new RuntimeException("set break-point default.");            }        }        @Override        public void run(){            System.out.println("#" + threadId + "---Thread is loading...");            makeSureTempFileExist();            writePartFile();            System.out.println("#" + threadId + "---Thread succeeded!");        }    }}
package cn.Down;/** * Created by donal on 2017/2/23. */public class DownUtilsTest {    public static void main(String[] args) {        DownUtils downUtils = new DownUtils("https://gss0.baidu.com/-Po3dSag_xI4khGko9WTAnF6hhy/zhidao/pic/item/d1a20cf431adcbef25b551dfaaaf2edda2cc9f61.jpg"            , "ais2.jpg",  5);        downUtils.download();        /*new Thread(new Runnable() {            @Override            public void run() {                while(downUtils.getCompleteRate() <1 ){                    System.out.println("已完成:" + downUtils.getCompleteRate());                    try {                        Thread.sleep(10);                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            }        });*/    }}
1 0
原创粉丝点击