java代码批量下载_Java代码实战:线程池实现批量下载文件

今天技术之家陪你一起Java代码实战:线程池实现批量下载文件:

1 创建线程池package com.cheng.webb.thread;

import java.util.concurrent.ArrayBlockingQueue;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.ThreadFactory;

import java.util.concurrent.ThreadPoolExecutor;

import java.util.concurrent.TimeUnit;

import java.util.concurrent.atomic.AtomicInteger;

public class ThreadUtil {

/**

* 创建批量下载线程池

*

* @param threadSize 下载线程数

* @return ExecutorService

*/

public static ExecutorService buildDownloadBatchThreadPool(int threadSize) {

int keepAlive = 0;

String prefix = "download-batch";

ThreadFactory factory = ThreadUtil.buildThreadFactory(prefix);

return new ThreadPoolExecutor(threadSize,

threadSize,

keepAlive,

TimeUnit.SECONDS,

new ArrayBlockingQueue<>(threadSize),

factory);

}

/**

* 创建自定义线程工厂

*

* @param prefix 名称前缀

* @return ThreadFactory

*/

public static ThreadFactory buildThreadFactory(String prefix) {

return new CustomThreadFactory(prefix);

}

/**

* 自定义线程工厂

*/

public static class CustomThreadFactory implements ThreadFactory {

private String threadNamePrefix;

private AtomicInteger counter = new AtomicInteger(1);

/**

* 自定义线程工厂

*

* @param threadNamePrefix 工厂名称前缀

*/

CustomThreadFactory(String threadNamePrefix) {

this.threadNamePrefix = threadNamePrefix;

}

@Override

public Thread newThread(Runnable r) {

String threadName = threadNamePrefix + "-t" + counter.getAndIncrement();

return new Thread(r, threadName);

}

}

}

2 批量下载文件package com.cheng.webb.thread;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import java.io.File;

import java.io.FileOutputStream;

import java.io.InputStream;

import java.net.HttpURLConnection;

import java.net.URL;

import java.util.ArrayList;

import java.util.List;

import java.util.Map;

import java.util.concurrent.*;

/**

* 文件下载类

*

* @author shucheng

* @creation 2019年1月30日下午4:41:32

*/

public class DownloadUtil {

private static Logger logger = LoggerFactory.getLogger(DownloadUtil.class);

/**

* 下载线程数

*/

private static final int DOWNLOAD_THREAD_NUM = 14;

/**

* 下载线程池

*/

private static ExecutorService downloadExecutorService = ThreadUtil

.buildDownloadBatchThreadPool(DOWNLOAD_THREAD_NUM);

/**

* 文件下载

*

* @param fileUrl

*            文件url,如:https://img3.doubanio.com//view//photo//s_ratio_poster//public//p2369390663.webp

* @param path

*            存放路径,如: /opt/img/douban/my.webp

*/

public static void download(String fileUrl, String path) {

// 判断存储文件夹是否已经存在或者创建成功

if (!createFolderIfNotExists(path)) {

logger.error("We can't create folder:{}", getFolder(path));

return;

}

InputStream in = null;

FileOutputStream out = null;

try {

URL url = new URL(fileUrl);

HttpURLConnection conn = (HttpURLConnection) url.openConnection();

conn.setRequestMethod("GET");

// 2s

conn.setConnectTimeout(10000);

in = conn.getInputStream();

out = new FileOutputStream(path);

int len;

byte[] arr = new byte[1024 * 1000];

while (-1 != (len = in.read(arr))) {

out.write(arr, 0, len);

}

out.flush();

conn.disconnect();

} catch (Exception e) {

logger.error("Fail to download: {} by {}", fileUrl, e.getMessage());

} finally {

try {

if (null != out) {

out.close();

}

if (null != in) {

in.close();

}

} catch (Exception e) {

// do nothing

}

}

}

/**

* 创建文件夹,如果文件夹已经存在或者创建成功返回true

*

* @param path

*            路径

* @return boolean

*/

private static boolean createFolderIfNotExists(String path) {

String folderName = getFolder(path);

if (folderName.equals(path)) {

return true;

}

File folder = new File(getFolder(path));

if (!folder.exists()) {

synchronized (DownloadUtil.class) {

if (!folder.exists()) {

return folder.mkdirs();

}

}

}

return true;

}

/**

* 获取文件夹

*

* @param path

*            文件路径

* @return String

*/

private static String getFolder(String path) {

int index = path.lastIndexOf("/");

return -1 != index ? path.substring(0, index) : path;

}

/**

* 下载资源

* issue: 线程池创建过多

* 最大批量下载为5,请知悉

*

* @param resourceMap

*            资源map, key为资源下载url,value为资源存储位置

*/

public static void batch(Map resourceMap) {

if (resourceMap == null || resourceMap.isEmpty()) {

return;

}

try {

List keys = new ArrayList<>(resourceMap.keySet());

int size = keys.size();

int pageNum = getPageNum(size);

for (int index = 0; index 

int start = index * DOWNLOAD_THREAD_NUM;

int last = getLastNum(size, start + DOWNLOAD_THREAD_NUM);

final CountDownLatch latch = new CountDownLatch(last - start);

// 获取列表子集

List urlList = keys.subList(start, last);

for (String url : urlList) {

// 提交任务

Runnable task = new DownloadWorker(latch, url, resourceMap.get(url));

downloadExecutorService.submit(task);

}

latch.await();

}

} catch (Exception e) {

logger.error("{}", e);

}

logger.info("Download resource map is all done");

}

/**

* 获取最后一个元素

*

* @param size

*            列表长度

* @param index

*            下标

* @return int

*/

private static int getLastNum(int size, int index) {

return index > size ? size : index;

}

/**

* 获取划分页面数量

*

* @param size

*            列表长度

* @return int

*/

private static int getPageNum(int size) {

int tmp = size / DOWNLOAD_THREAD_NUM;

return size % DOWNLOAD_THREAD_NUM == 0 ? tmp : tmp + 1;

}

/**

* 下载线程

*/

static class DownloadWorker implements Runnable {

private CountDownLatch latch;

private String url;

private String path;

DownloadWorker(CountDownLatch latch, String url, String path) {

this.latch = latch;

this.url = url;

this.path = path;

}

@Override

public void run() {

logger.debug("Start batch:[{}] into: [{}]", url, path);

DownloadUtil.download(url, path);

logger.debug("Download:[{}] into: [{}] is done", url, path);

latch.countDown();

}

}

}

3 测试批量下载文件package com.cheng.webb.thread;

import java.util.HashMap;

import java.util.Map;

import org.junit.Test;

import com.alibaba.fastjson.JSON;

public class DownLoadTest {

String json = "{\r\n"

+ "\"http://www.xxx.com/111/123.mp4\":\"myFile/111/123.mp4\",\r\n"

+ "\"http://www.xxx.com/111/124.mp4\":\"myFile/111/124.mp4\",\r\n"

+ "\"http://www.xxx.com/111/125.mp4\":\"myFile/111/125.mp4\"\r\n"

+ "}";

@SuppressWarnings("unchecked")

@Test

public void test() {

Map map = new HashMap<>();

Map resMap = JSON.parseObject(json, map.getClass());

int times = 1;

for (int index = 0; index 

DownloadUtil.batch(resMap);

}

}

}

技术之家希望本篇文章对你有用!!

欢迎来到技术之家,

如需转载,烦请保留本文链接和出处:http://www.jszja.com/contents/14/1440.html

您的支持将是我们前进的动力!如对本篇文章有疑问或建议,请通过本站下方邮箱联系我们,让技术之家每天进步一点点!(●'◡'●)

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值