package com.example.demo.controller;
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.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@RequestMapping("/upload3")
@RestController
public class uploadController {
//定义分片有多大
private final static long PER_PAGE=1024l*1024l*50l;
//设置分片存储的临时目录
private final static String DOWN_PATH="C:\\Users\\Lenovo\\Desktop\\lianxi";
//下载文件的地址
private final static String url="http://localhost:8080/upload3/downLoad/";
//文件存放的位置
private final static String pathfile=System.getProperty("user.dir")+"\\static\\upload\\";
ExecutorService pool= Executors.newFixedThreadPool(10);
//文件大小文件名字
// 探测 获取文件信息
// 多线程分片下载
//最后一个分片下载完 始合并
@RequestMapping("/downLoadFile/{filename}")
public void downLoadFile(@PathVariable("filename") String filename) throws IOException, InterruptedException {
FileInfo fileInfo = download(0, 10, -1, null,filename);
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,filename));
}
}
}
class DownLoad implements Runnable{
long start;
long end;
long page;
String fName;
String fileName;
public DownLoad(long start, long end, long page, String fName, String fileName) {
this.start = start;
this.end = end;
this.page = page;
this.fName = fName;
this.fileName = fileName;
}
@Override
public void run() {
try {
download(start,end,page,fName,fileName);
} catch (IOException e) {
throw new RuntimeException(e);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
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,String fileName) 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(url+fileName);
httpGet.setHeader("Range","bytes="+start+"-"+end);
HttpResponse response = client.execute(httpGet);
String fSize = response.getFirstHeader("fSize").getValue();
fName= URLDecoder.decode(response.getFirstHeader("fName").getValue(),"utf-8");
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.valueOf(fSize)>0){
mergeFile(fName,page);
}
return new FileInfo(Long.valueOf(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 temFile = new File(DOWN_PATH, i + "-" + fName);
while (!file.exists()||(i!=page && temFile.length()<PER_PAGE)){
Thread.sleep(100);
}
byte[] bytes= FileUtils.readFileToByteArray(temFile);
os.write(bytes);
os.flush();
temFile.delete();
}
File file1=new File(DOWN_PATH,-1+"-null");
file1.delete();
os.flush();
os.close();
}
@RequestMapping("/downLoad/{filename}")
public void downLoadFile(@PathVariable("filename") String filename, HttpServletResponse response, HttpServletRequest request) throws IOException {
//文件存在的路径
String path = pathfile+filename;
//String path="D:\\java 录屏\\20231216_183319.mp4";
File file = new File(path);
if(!file.exists()){
return;
}
//设置编码
response.setCharacterEncoding("utf-8");
//输入输出对象
InputStream is=null;
OutputStream os=null;
//关闭流try
try{
//分片下载
//获取文件长度
long fSize=file.length();
//设置头
response.setContentType("application/x-download");
String fileName= URLEncoder.encode(file.getName(),"utf-8");
//让前端弹出对话框下到哪里
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 (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 rangeLenght = last - pos + 1;
String contentRange=new StringBuffer("bytes ").append(pos).append("-").append(last).append("/").append(fSize).toString();
response.setHeader("Content-Range",contentRange);
response.setHeader("Cotent-Lenght",String.valueOf(rangeLenght));
os=new BufferedOutputStream(response.getOutputStream());
is=new BufferedInputStream(new FileInputStream(file));
is.skip(pos);
byte[] buffer=new byte[1024];
int lenght=0;
while (sum<rangeLenght){
lenght=is.read(buffer,0,((rangeLenght-sum)<=buffer.length?((int)(rangeLenght-sum)):buffer.length));
sum=sum+lenght;
os.write(buffer,0,lenght);
}
}finally {
if (is!=null){
is.close();
}
if (os!=null){
os.close();
}
}
}
}
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
访问路径:localhost:8080/upload3/downLoadFile/下载的东西
传递的参数:下载的文件名