您当前的位置: 首页 >  Java

命运之手

暂无认证

  • 3浏览

    0关注

    747博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

【Java】【断点续传】大文件断点续传实现方案和原理

命运之手 发布时间:2021-12-23 17:59:06 ,浏览量:3

实现思路

  • 断点续传是Http协议自带的功能,通用的文件下载服务,都支持这个特性
  • 比如Tomcat服务器,NodeJs服务器,SpringBoot内置的FileSystemResource,都支持该特性,实现起来一般几行代码即可
  • 断点续传的工作原理大致如下
  • 首先,客户端获取文件总长度,客户端在请求头中设置Accept-Encoding=identity
  • 然后服务端会在回复头中返回Content-Length,即文件总长度
  • 客户端在下载文件时,可以在请求头中设置range=bytes=start-end,指定只下载start-end部分的文件字节
  • 这样客户端就能分多次下载,每次只下载一部分
  • 带有range参数的请求,成功返回的ResponseCode是206,而不是200,表示局部下载

大致代码

以下代码中包含了很多工具类库,是无法直接使用的

主要是展示断点续传的核心思路,大家将其中的工具和请求库,替换成自己的代码即可


    public static void main(String[] args) {
        DownloadConfig config = new DownloadConfig();
        config.url = "http://192.168.8.124:18001/common/file/download/bdce9ddd7cda4e81bdf7e80d49f0c636.apk";
        config.name = TextUtil.random();
        config.ext = ".apk";
        config.file();
        FileDownloader.start(config);
    }


	public class DownloadConfig {
	
	    public String url;
	    public String name;
	    public String ext;
	    public Long total;
	    public Long finish;
	    public String percent = "0%";
	    public String file;
	
	    public boolean finished() {
	        return total != null && finish != null && finish.intValue() == total.intValue();
	    }
	
	    public void file() {
	        file = "C:/" + name + ext;
	        FileUtil.createFile(file);
	    }
	}


	public class FileDownloader {
	
	    //开始下载
	    public static void start(DownloadConfig config) {
	        while (true) {
	            if (config.finished()) {
	                Threads.sleep(1000);
	                break;
	            }
	            if (config.total == null)
	                obtainFileLength(config);
	            else
	                downloadFilePart(config);
	            Threads.sleep(100);
	        }
	    }
	
	    //获取文件长度
	    protected static void obtainFileLength(DownloadConfig config) {
	        Postman.create()
	                .url(config.url)
	                .method(HttpMethod.GET)
	                .head("Accept-Encoding", "identity")
	                .onException((postman, call, e) -> {
	                    Console.error("PackageDownloader obtainFileLength fail");
	                })
	                .onResponse((postman, call, response) -> {
	                    String length = response.headers().get("Content-Length");
	                    config.total = Long.valueOf(length);
	                    config.finish = 0L;
	                    config.percent = "0%";
	                }).executeInBlocking();
	    }
	
	    //下载文件片段
	    protected static void downloadFilePart(DownloadConfig config) {
	        final long start = config.finish;
	        final long end = start + 10 * 1024 * 1024 > config.total - 1 ? config.total - 1 : start + 10 * 1024 * 1024;
	        Postman.create()
	                .url(config.url)
	                .method(HttpMethod.GET)
	                .head("range", "bytes=" + start + "-" + end)
	                .onException((postman, call, e) -> {
	                    Console.error("PackageDownloader obtainFileLength fail");
	                })
	                .onResponse((postman, call, response) -> {
	                    byte[] bytes = response.body().bytes();
	                    FileUtil.randomWrite(config.file, bytes, config.total, start);
	                    config.finish = end + 1;
	                    config.percent = config.finish / (double) config.total + "";
	                    if (config.finished())
	                        config.percent = "100%";
	                }).executeInBlocking();
	    }
	}

关注
打赏
1654938663
查看更多评论
立即登录/注册

微信扫码登录

0.0507s