从服务器下载文件

java Springboot实现文件下载

package com.example.yjznsb.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;

@Controller
public class downloadController {
    static String utf8 = "utf-8";
    @RequestMapping("/download")
    @ResponseBody
    public void downloadFile(HttpServletRequest request, HttpServletResponse response) throws IOException {
        // 需要下载的文件,没有设置参数,直接写死了
        File file = new File("C:\\Users\\MissLiuAndMrWang\\Desktop\\taoci\\1.sql");
        response.setCharacterEncoding(utf8);
        // 输入输出流
        InputStream is = null;
        OutputStream os = null;
        try {
            // 分片下载  http Range bytes=100-1000
            long fSize = file.length();
            // 设置为下载的报头
            response.setContentType("application/x-download");
            // 设置编码
            String fileName = URLEncoder.encode(file.getName(),utf8);

            response.addHeader("Content-Disposition","attachment;filename="+fileName);
            response.setHeader("Accept-Range","bytes");

            response.setHeader("fSize",String.valueOf(fSize));
            response.setHeader("fName",fileName);

            // 分片去读取文件
            long pos =0,last = fSize-1,sum = 0;
            // 判断是否需要分片下载  如果需要则近if
            if(null!=request.getHeader("Range")){
                response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);

                String numRange = request.getHeader("Range").replaceAll("bytes=","");
                String[] strRange = numRange.split("-");
                if(strRange.length == 2){
                    pos = Long.parseLong(strRange[0].trim());
                    last = Long.parseLong(strRange[1].trim());
                    if(last > fSize-1){
                        last = fSize - 1;
                    }
                }else {
                    pos = Long.parseLong(numRange.replaceAll("-","").trim());
                }
            }

            long rangeLength = last - pos + 1;
            String contentRange = new StringBuffer("bytes ").append(pos).append(last).append("/").append(fSize).toString();
            response.setHeader("context-Range",contentRange);
            response.setHeader("context-Length",String.valueOf(rangeLength));

            os = new BufferedOutputStream(response.getOutputStream());
            is = new BufferedInputStream(new FileInputStream(file));
            is.skip(pos);
            byte[] buffer = new byte[1024];
            int length = 0;
            // 开始写入
            while(sum < rangeLength){
                // 每次读取0-1023长度的字符
                length = is.read(buffer,0, (rangeLength-sum) <= buffer.length? (int) (rangeLength - sum) :buffer.length);
                sum = sum + length;
                os.write(buffer,0,length);
            }
            System.out.println("下载完成");
        }finally {
            if(is!=null){
                is.close();
            }
            if(os!=null){
                os.close();
            }
        }
    }
}

上面直接访问的话无法用到分片下载部分,下面代码是客户端下载时,应用分片下载

package com.example.yjznsb.client;

import org.apache.commons.io.FileUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClients;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.*;
import java.net.URLDecoder;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


@RestController
public class DownloadClient {

    // 定义每一个分片的大小 5MB
    private final static long PER_PAGE=1024 * 1024 * 50;
    // 分片存储的临时目录
    private final static String DOWN_PATH="C:\\Users\\MissLiuAndMrWang\\Desktop\\springUpload\\src\\main\\java\\com\\example\\yjznsb\\client";
    //多线程 定义应该线程值
    ExecutorService pool = Executors.newFixedThreadPool(10);

    // 文件大小 分片大小 决定分片数量  文件名字
    // 探测  实验性的下载获取文件信息
    // 使用多线程文件下载
    // 最后一个分片下载完 开始合并
    @RequestMapping("/downloadClient")
    public String downloadFile() throws IOException, InterruptedException {
        FIleInfo fIleInfo = download(0,10,-1,null);
        if (fIleInfo!=null){
            long pages = fIleInfo.fSize/PER_PAGE;
            for(long i=0; i < pages;i++){
                pool.submit(new Download(i*PER_PAGE,(i+1)*PER_PAGE-1,i,fIleInfo.fName));
            }
        }
        return "success";
    }

    class Download implements Runnable{
        long start ;
        long end;
        long page;
        String fName;

        public Download(long start, long end, long page, String fName) {
            this.start = start;
            this.end = end;
            this.page = page;
            this.fName = fName;
        }

        @Override
        public void run() {
            try {
                download(start,end,page,fName);
            } catch (IOException | InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    class FIleInfo{
        long fSize;
        String fName;

        public FIleInfo(long fSize, String fName) {
            this.fSize = fSize;
            this.fName = fName;
        }
    }

    // 分片下载的开始位置,结束位置
    // 结束位置 - 开始位置 = 分片大小
    // 临时存储 分片文件
    private FIleInfo download(long start, long end,long page, String fName) throws IOException, InterruptedException {
        // 断点下载
        File file = new File(DOWN_PATH,page+"-"+fName);
        if(file.exists() && page != -1 && file.length() == PER_PAGE){
            return null;
        }
        HttpClient client = HttpClients.createDefault();
        HttpGet httpGet = new HttpGet("http://127.0.0.1:8080/download");
        httpGet.setHeader("Range","bytes="+start+"-"+end);

        HttpResponse response = client.execute(httpGet);
        String fSize = response.getFirstHeader("fSize").getValue();
        fName = URLDecoder.decode(response.getFirstHeader("fName").getValue());

        HttpEntity entity = response.getEntity();
        InputStream is = entity.getContent();

        // 输出流
        FileOutputStream fos = new FileOutputStream(file);
        // 缓冲区
        byte[] buffer = new byte[1024];
        int ch;
        while((ch = is.read(buffer))!=-1){
            fos.write(buffer,0,ch);
        }
        is.close();
        fos.flush();
        fos.close();
        // 判断是否是最后一个分片 如果是 则合并
        if(end-Long.parseLong(fSize)>0){
            mergeFile(fName,page);
        }
        return new FIleInfo(Long.parseLong(fSize),fName);
    }
//  合并文件部分代码
    private void mergeFile(String fName, long page) throws IOException, InterruptedException {
        File file = new File(DOWN_PATH,fName);
        BufferedOutputStream os = new BufferedOutputStream(new FileOutputStream(file));

        for(int i=0; i<=page; i++){
            File tempFile = new File(DOWN_PATH,i+"-"+fName);
            while(!file.exists() || (i!=page && tempFile.length()<PER_PAGE)){
                Thread.sleep(100);
            }
            byte[] bytes = FileUtils.readFileToByteArray(tempFile);
            os.write(bytes);
            os.flush();
            tempFile.delete();
            File file1 = new File(DOWN_PATH,-1+"-null");
            file1.delete();
            os.flush();
            os.close();
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值