java多线程下载文件
package com.study;
import javax.net.ssl.*;
import java.io.*;
import java.net.URL;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 多线程下载文件
* @Author: lhs
* @Date: 2024/3/17 16:16
*/
public class FastDowload {
private static String url = "https://www.xx.com/5236.mp4";
static String fileName = "资料";// 保存文件名
static String saveDir = "c:/temp/";// 保存目录
private static int limit = 1024 * 1024; // 分段下载,每一段文件大小1M
private static int N = 16;// 线程数16
public static void main(String[] args) {
downloadFile();
}
/**
* 下载文件
*/
public static void downloadFile() {
try {
// 文件总大小,单位:字节
int size = getFileSize(url);
// 分段下载,分几段
int count = (size + limit - 1) / limit;
AtomicInteger atomic = new AtomicInteger(0); // 分段下标
AtomicInteger success = new AtomicInteger(0); // 下载成功个数
// 下载线程池
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(N);
for (int i = 0; i < count; i++) {
fixedThreadPool.execute(() -> {
// 随机获取一个下标,获取其中一个文件
int index = atomic.getAndIncrement(); // 先返回,后自增
int start = index * limit;
int end = (index + 1) * limit - 1;
String range = start + "-" + end;
// 最后一段请求头
if (index == count - 1) {
range = start + "-";
}
// 失败后重试,最多重试50次
for (int j = 0; j < 50; j++) {
try {
byte[] bytes = sendGet(url, range);
if (bytes == null) {
System.out.println(count + "下载000" + (index + 1) + "失败:" + (j + 1) + "次," + range);
continue;
}
saveFile(bytes, "000" + (index + 1) + ".tmp");
System.out.println(count + "下载000" + (index + 1) + "成功:" + range);
success.getAndIncrement(); // 先返回,后自增
return;
} catch (Exception e) {
System.out.println(count + "下载000" + (index + 1) + "失败:" + (j + 1) + "次," + range);
}
}
System.out.println(count + "下载失败到达最大次数:下载000" + (index + 1) + "失败:" + range);
});
}
fixedThreadPool.shutdown();
// 等待子线程结束,再继续执行下面的代码
fixedThreadPool.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
System.out.println("所有文件下载结束,总共:" + count + "个文件!,成功:" + success.get() + "个文件!");
// 合并文件
mergeFile(count);
System.out.println("合并完成,总共:" + count + "个文件!");
// 删除文件
deleteFile(count);
System.out.println("成功,总共:" + count + "个文件!");
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 保存文件
*/
private static void saveFile(byte[] bytes, String name) {
FileOutputStream fos = null;
try {
fos = new FileOutputStream(saveDir + name);
fos.write(bytes);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 删除文件
*/
private static void deleteFile(int count) {
for (int i = 0; i < count; i++) {
new File(saveDir + "000" + (i + 1) + ".tmp").delete();
}
}
/**
* 合并文件
*/
private static void mergeFile(int count) {
FileOutputStream fos = null;
try {
if ("".equals(fileName)) {
fileName = "1" + new Random().nextInt(10000);
}
File file = new File(saveDir + fileName + ".mp4");
fos = new FileOutputStream(file);
int len;
byte[] buf = new byte[4096];
for (int i = 0; i < count; i++) {
FileInputStream fis = new FileInputStream(saveDir + "000" + (i + 1) + ".tmp");
while ((len = fis.read(buf)) != -1) {
fos.write(buf, 0, len);
}
fos.flush();
fis.close();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (fos != null) {
fos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 获取文件大小
*/
private static int getFileSize(String url) {
HttpsURLConnection connection = null;
try {
connection = (HttpsURLConnection) new URL(url).openConnection();
// 绕过证书验证
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, new TrustManager[]{new MyTrustManager()}, new java.security.SecureRandom());
connection.setSSLSocketFactory(sc.getSocketFactory());
connection.setHostnameVerifier(new MyHostnameVerifier());
connection.setConnectTimeout(5000);
connection.setReadTimeout(5000);
connection.connect();
String contentLength = connection.getHeaderField("Content-Length");
return Integer.parseInt(contentLength);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (connection != null) {
connection.disconnect();
}
}
return 0;
}
/**
* 下载其中一段文件
*/
public static byte[] sendGet(String url, String range) {
HttpsURLConnection connection = null;
InputStream is = null;
try {
connection = (HttpsURLConnection) new URL(url).openConnection();
// 绕过证书验证
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, new TrustManager[]{new MyTrustManager()}, new java.security.SecureRandom());
connection.setSSLSocketFactory(sc.getSocketFactory());
connection.setHostnameVerifier(new MyHostnameVerifier());
connection.setConnectTimeout(5000);
connection.setReadTimeout(30000);
// 下载其中一段文件
connection.setRequestProperty("Range", "bytes=" + range);
connection.connect();
is = connection.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int len;
byte[] buf = new byte[1024];
while ((len = is.read(buf)) != -1) {
baos.write(buf, 0, len);
baos.flush();
}
return baos.toByteArray();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (is != null) {
is.close();
}
if (connection != null) {
connection.disconnect();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
static class MyTrustManager implements X509TrustManager {
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[]{};
}
}
static class MyHostnameVerifier implements HostnameVerifier {
@Override
public boolean verify(String urlHostName, SSLSession session) {
return true;
}
}
}