使用Java多线程将大文件分解,并下载大文件

详解超大文件上传下载方案(JAVA) 要求:开源,免费,技术支持技术:分片,分块,断点续传,加密传输,加密存储需求:大文件上传,批量上传,断点续传,文件夹上传,大文件下载,批量下载,断点下载,文件夹下载文件夹:上传下载需要支持层级结构,采用非压缩方式文件大小:100G前端:vue2,vue3,vue-cli,jquery,html,webuploader后端:java,JSP,springboot,struts服务器:linux,信创国产化数据库:mysql,oracle,达梦,国产化数据库。 阅读详情

主要思路是将大文件分解成若干个小文件进行下载.

本功能由两个类实现:DownLoadManager和DownloadThreadTask实现. 其中DownLoadManager类主要负责下载任务的初始化和调度, DownloadThreadTask主要负责处理下载任务.

用到的主要工具类有

  1. org.apache.http.impl.client.CloseableHttpClient 模拟httpClient客户端发送http请求,可以控制到请求文件的字节位置。

  2. BufferedInputStream都熟悉,用它接受请求来的流信息缓存。

  3. RandomAccessFile文件随机类,可以向文件写入指定位置的流信息。

代码如下:

DownLoadManager

package util;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
 * 文件下载管理类
 */
public class DownLoadManager{
    private static final Logger LOGGER = LoggerFactory.getLogger(DownLoadManager.class);
    /**
     * 每个线程下载的字节数
     */
    private long unitSize = 1000 * 1024;
    private ExecutorService taskExecutor = Executors.newFixedThreadPool(10);
    
    private CloseableHttpClient httpClient;

    public DownLoadManager() {
        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
        cm.setMaxTotal(100);
        httpClient = HttpClients.custom().setConnectionManager(cm).build();
    }
    public static void main(String[] args) throws IOException {
        new DownLoadManager().doDownload();
    }
    /**
     * 启动多个线程下载文件
     */
    public void doDownload() throws IOException {
        //要下载的url
        String remoteFileUrl = "http://cn-sdjn-cu-v-04.acgvideo.com/vg4/e/60/21029304-1.mp4?expires=1504513500&platform=pc&ssig=4-pYfuQHUKppz3XGrw6Hnw&oi=1032322900&nfa=T7l/1XWXSxfil4KoioiGpQ==&dynamic=1&hfa=2073962963&hfb=Yjk5ZmZjM2M1YzY4ZjAwYTMzMTIzYmIyNWY4ODJkNWI=";
        String localPath = "E://temp//";
        String fileName = new URL(remoteFileUrl).getFile();
        System.out.println("远程文件名称:" + fileName);
        fileName = fileName.substring(fileName.lastIndexOf("/") + 1, fileName.length()).replace("%20", " ");

        System.out.println("本地文件名称:" + fileName);
        long fileSize = this.getRemoteFileSize(remoteFileUrl);
        this.createFile(localPath + System.currentTimeMillis() + fileName, fileSize);
        Long threadCount = (fileSize / unitSize) + (fileSize % unitSize != 0 ? 1 : 0);
        long offset = 0;
        
        CountDownLatch end = new CountDownLatch(threadCount.intValue());
        if (fileSize <= unitSize) {// 如果远程文件尺寸小于等于unitSize
            DownloadThreadTask downloadThread = new DownloadThreadTask(remoteFileUrl, localPath + fileName, offset, fileSize, end, httpClient);
            taskExecutor.execute(downloadThread);
        } else {// 如果远程文件尺寸大于unitSize
            for (int i = 1; i < threadCount; i++) {
                DownloadThreadTask downloadThread = new DownloadThreadTask(remoteFileUrl, localPath + fileName, offset, unitSize, end, httpClient);
                taskExecutor.execute(downloadThread);
                offset = offset + unitSize;
            }
            if (fileSize % unitSize != 0) {// 如果不能整除,则需要再创建一个线程下载剩余字节
                DownloadThreadTask downloadThread = new DownloadThreadTask(remoteFileUrl, localPath + fileName, offset, fileSize - unitSize * (threadCount - 1), end, httpClient);
                taskExecutor.execute(downloadThread);
            }
        }
        try {
            end.await();
        } catch (InterruptedException e) {
            LOGGER.error("DownLoadManager exception msg:{}", ExceptionUtils.getFullStackTrace(e));
            e.printStackTrace();
        }
        taskExecutor.shutdown();
        LOGGER.debug("下载完成!{} ", localPath + fileName);
    }

    /**
     * 获取远程文件尺寸
     */
    private long getRemoteFileSize(String remoteFileUrl) throws IOException {
        long fileSize = 0;
        HttpURLConnection httpConnection = (HttpURLConnection) new URL(remoteFileUrl).openConnection();
        //使用HEAD方法
        httpConnection.setRequestMethod("HEAD");
        int responseCode = httpConnection.getResponseCode();
        if (responseCode >= 400) {
            LOGGER.debug("Web服务器响应错误!");
            return 0;
        }
        String sHeader;
        for (int i = 1;; i++) {
            sHeader = httpConnection.getHeaderFieldKey(i);
            if (sHeader != null && sHeader.equals("Content-Length")) {
                System.out.println("文件大小ContentLength:" + httpConnection.getContentLength());
                fileSize = Long.parseLong(httpConnection.getHeaderField(sHeader));
                break;
            }
        }
        return fileSize;
    }

    /**
     * 创建指定大小的文件
     */
    private void createFile(String fileName, long fileSize) throws IOException {
        File newFile = new File(fileName);
        RandomAccessFile raf = new RandomAccessFile(newFile, "rw");
        raf.setLength(fileSize);
        raf.close();
    }
}

DownloadThreadTask

package util;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.concurrent.CountDownLatch;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 负责文件下载的类
 */
public class DownloadThreadTask implements Runnable {

    private static final Logger LOGGER = LoggerFactory.getLogger(DownloadThreadTask.class);

    /**
     * 待下载的文件
     */
    private String url = null;

    /**
     * 本地文件名
     */
    private String fileName = null;

    /**
     * 偏移量
     */
    private long offset = 0;

    /**
     * 分配给本线程的下载字节数
     */
    private long length = 0;
    
    private CountDownLatch end;
    private CloseableHttpClient httpClient;
    private HttpContext context;

    /**
     * @param url
     *            下载文件地址
     * @param fileName
     *            另存文件名
     * @param offset
     *            本线程下载偏移量
     * @param length
     *            本线程下载长度
     */
    public DownloadThreadTask(String url, String file, long offset, long length, CountDownLatch end, CloseableHttpClient httpClient) {
        this.url = url;
        this.fileName = file;
        this.offset = offset;
        this.length = length;
        this.end = end;
        this.httpClient = httpClient;
        this.context = new BasicHttpContext();
        LOGGER.debug("偏移量=" + offset + ";字节数=" + length);
    }
    
    public void run() {
        try {
            HttpGet httpGet = new HttpGet(this.url);
            httpGet.addHeader("Range", "bytes=" + this.offset + "-" + (this.offset + this.length - 1));
            httpGet.addHeader("Referer", "http://api.bilibili.com");
            CloseableHttpResponse response = httpClient.execute(httpGet, context);
            BufferedInputStream bis = new BufferedInputStream(response.getEntity().getContent());
            byte[] buff = new byte[1024];
            int bytesRead;
            File newFile = new File(fileName);
            RandomAccessFile raf = new RandomAccessFile(newFile, "rw");
            while ((bytesRead = bis.read(buff, 0, buff.length)) != -1) {
                raf.seek(this.offset);
                raf.write(buff, 0, bytesRead);
                this.offset = this.offset + bytesRead;
            }
            raf.close();
            bis.close();
        } catch (ClientProtocolException e) {
            LOGGER.error("DownloadThread exception msg:{}", ExceptionUtils.getFullStackTrace(e));
        } catch (IOException e) {
            LOGGER.error("DownloadThread exception msg:{}", ExceptionUtils.getFullStackTrace(e));
        } finally {
            end.countDown();
            LOGGER.info(end.getCount() + " is go on!");
            System.out.println(end.getCount() + " is go on!");
        }
    }
}
Spring Boot实现HTTP大文件断点续传分片下载-大视频分段渐进式播放 如果碰到网络故障,可以从已经上传/下载的部分开始继续上传/下载未完成的部分,而没有必要从头开始上传/下载。有时,用户上传/下载文件需要历时数小时,万一线路中断,不具备断点续传的 HTTP/FTP 服务器或下载软件就只能从头重传,所以如果服务器或下载软件具有断点续传能力,允许用户从上传/下载断线的地方继续传送,这样就大大减少了用户的烦恼。* SpringBoot 实现Http分片下载断点续传,从而实现H5页面的大视频播放问题,实现渐进式播放,每次只播放需要播放的内容就可以了,不需要加载整个文件到内存中。 阅读详情

相关推荐

Java多线程下载实现:简单示例与步骤详解

简介:Java中的多线程技术通过允许程序同时执行多个任务来提高效率。特别是在处理大文件下载时,利用多线程可以显著优化性能。本篇文章将指导读者如何在Java中实现多线程下载,并提供一个简单且详细的示例,包括线程创建、文件分割、任务执行和文件合并的步骤。

weixin_42143092的博客 1134

【Java流式下载大文件,避免OOM内存溢出】

Java下载文件时,如果是小文件的下载,我们一般直接使用工具类的方法,比如cn.hutool.http.HttpUtil.downloadFile()。但是如果是大文件的下载,使用这些工具类的方法,可能会出现Out of Memory内存溢出,它是指需要的内存空间大于系统分配的内存空间,oom后果就是项目程序crash,Hprof Heap Profile 内存快照文件。

weixin_39825906的博客 1万+

Java多线程高效文件下载:分片并行处理技术

本文还有配套的精品资源,点击获取 简介:Java多线程文件下载是一种提高大文件下载效率的方法,它将文件分割成多个片段,并为每个片段创建独立线程进行下载,从而实现并行下载。这种方法可以优化网络不稳定或大文件下载的性能,因为即使某个线程中断,其他线程仍能继续工作。本技术介绍如何通过Java多线程实现文件分片下载,包括线程池的使用、下载任务创建、线程同步控制、异常处理、进度反馈以...

weixin_42327217的博客 1996

java大文件上传,大文件下载解决方案

将大文件分成小块,分别上传,然后在服务器端将这些块合并成一个完整的文件。这适用于小文件,但不太适合大文件,因为需要将整个文件加载到内存中。大文件分片上传是一种常见的策略,它可以减少单次上传的负担,并且支持在上传过程中断点续传。它支持流式处理文件,适用于大文件上传。使用HTTP的Range请求头,允许在下载时请求文件的指定部分,从而支持分段下载。在下载时,客户端和服务器之间维护已下载的字节数,当连接中断时可以从中断处继续下载,减少数据重复下载。如果文件存储在云存储中,使用相应的云存储API进行文件下载。

pengzong_的博客 4187

用java写的进行文件处理的代码

有两个txt文件,一个里面是字符串,现在要将字符串中的第几行和第几行的字符串给换掉,另外一个txt里是: 1/ta 2/tb 3/tc 将两行的字符串换成1和a,生成到一个文件里,再换成2和b,生成一个文件

STM32H743 ADC多通道采样实战:CubeMX配置+DMA传输避坑指南

本文详细介绍了STM32H743 ADC多通道采样的实战配置,包括CubeMX参数设置、DMA传输优化及常见问题解决方案。重点解析了ADC模块的核心特性、多通道采样序列配置、Cache一致性处理等关键技术,帮助开发者高效实现稳定可靠的模拟信号采集系统。

weixin_29175469的博客 611

【java】java实现大文件的分片上传与下载(springboot+vue3)

对于超大文件上传我们可能遇到以下问题 • 大文件直接上传,占用过多内存,可能导致内存溢出甚至系统崩溃 • 受网络环境影响,可能导致传输中断,只能重新传输 • 传输时间长,用户无法知道传输进度,用户体验不佳对于上述问题,我们需要对文件做分片传输。分片传输就是把文件分割成许多较小的文件,然后分多次上传,最后再完成合并。受网络环境影响,我们还要实现断点续传,以节省传输时间和资源。断点续传就是已经上传或者下载过的文件分片不再传输。对于已经上传过的文件,可以不再上传,实现秒传。秒传就是根据文件的唯一标识,确认是否需要

橙子的博客 2万+

ISO26262 功能安全各个阶段测试要求

1. 开发过程说明 系统层面:包括软硬件集成测试、系统集成测试以及整车测试。 硬件层面:包括硬件集成与测试。 软件层面:单元测试、集成测试。 2. 功能安全总体要求 2.1 各项指标 2.2 诊断覆盖度举例 针对一个信号举例说明: 3. 功能安全测试要求 3.1 测试计划 核心内容应包括, 测试对象:需要测试的对象描述,以及测试的范围描...

AgingMoon的博客 1万+

java 大文件下载_使用Java下载大文件

title: 使用Java下载大文件date: 2017-09-04 04:51:12tags: [Java]主要思路是将大文件分解成若干个小文件进行下载.本功能由两个类实现:DownLoadManager和DownloadThreadTask实现. 其中DownLoadManager类主要负责下载任务的初始化和调度, DownloadThreadTask主要负责处理下载任务.用到的主要工具类有o...

weixin_39571219的博客 2121

从‘平行’到‘鱼骨’:手把手拆解AlGaN/GaN HEMT多栅指结构的布局优化实战

本文深入探讨了AlGaN/GaN HEMT多栅指结构的布局优化,从传统的平行栅结构到创新的鱼骨栅结构,详细解析了如何通过优化信号路径和热管理提升功率器件的性能。文章结合实测数据和EDA工具,展示了鱼骨栅结构在相位一致性、热阻和版图利用率方面的显著改进,为射频功率放大器设计提供了实用指导。

weixin_27061475的博客 439

Win10 LTSC 2021 CPU占用率飙升?KB5017308补丁修复全攻略

本文针对Windows 10 LTSC 2021系统中因wsappx进程导致的CPU占用率异常飙升问题,提供了详细的解决方案。核心在于安装微软官方发布的KB5017308补丁,该补丁能从根本上修复系统组件缺陷,使CPU占用恢复正常。文章详解了补丁的下载、安装步骤、注意事项及安装后的验证方法,是解决此问题的权威指南。

python9snake的博客 1257

超大文件下载

主要思路是将大文件分解成若干个小文件进行下载. 本功能由两个类实现:DownLoadManager和DownloadThreadTask实现. 其中DownLoadManager类主要负责下载任务的初始化和调度, DownloadThreadTask主要负责处理下载任务. 用到的主要工具类有 org.apache.http.impl.client.CloseableHttpClient 模拟httpClient客户端发送http请求,可以控制到请求文件的字节位置。 BufferedInputStream都熟

lijie13426069132的博客 5256

AJ-Report开源数据大屏存在远程命令执行漏洞

该平台可以通过post方式在validationRules参数对应值中进行命令执行,可以获得服务器权限,登陆管理后台接管大屏。如果被攻击者利用,危害后果十分严重。

swordheart的博客 387

多线程教学、多线程下载网络图片、视频等

多线程下载网络图片or视频等内容

ayearinglife的博客 740

那些年对支付宝的研究[整理]

支付宝功能强大.他内部各个功能间的跳转是通过Uri 实现的.而使用window.location.href 即可.跟浏览器一样的协议.很方便 H5启动支付宝: alipays://platformapi/startapp?appId=20000067&url=网址 alipays://platformapi/startapp?appId=20000691&url=网址 ali...

技术专研 8914

【STK】手把手教你利用STK进行光电红外仿真04-STK/EOIR模块的实战操作1航天器星载相机对LEO卫星成像

今天引入一个实际的场景,帮助大家完成对于这个模块的理解与运用。

weixin_44184852的博客 2417

使用ForkJoin方式实现多线程下载功能

起因 本人在看了 Java实现多线程下载文件 这篇博客后突发想法而做。 那篇文章利用Callable类和线程池实现多线程下载。其原理是:先使用head方法查询得到对应文件的Content-Length,然后拆分成多个部分,交由多个线程去处理,使用"Range", "bytes=" + star...

chihuang7920的博客 597

基于知识图谱的档案智慧问答系统:构建智能化档案管理与知识服务新范式

基于知识图谱的档案智慧问答系统是档案管理领域的一次重要创新,它通过将档案数据转化为结构化的知识图谱,并结合自然语言处理和智能问答技术,实现了档案信息的智能化管理与服务。该系统不仅能够提升档案管理的效率,还能为用户提供更全面、更便捷的知识服务,具有广泛的应用前景和深远的社会意义。未来,随着技术的不断进步和应用场景的不断扩展,基于知识图谱的档案智慧问答系统将在更多领域发挥其价值,为档案管理领域的智能化转型提供强有力的支持。

qq_62634009的博客 1575

探索`zc-downloader`: 一个高效、灵活的多线程下载工具

探索zc-downloader: 一个高效、灵活的多线程下载工具 在如今的信息时代,我们常常需要下载大量的文件,无论是工作资料还是娱乐资源。这就是zc-downloader项目的用武之地。这个开源项目()旨在提供一个快速且可自定义的多线程下载解决方案,帮助用户提升下载效率。 项目简介 zc-downloader是一个基于Java编写的命令行工具,它利用多线程技术,可以将大型文件分割成多个部分并同时...

gitblog_00044的博客 541

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

多线程下载

多线程下载的使用的方法是w

hey Man 608

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

java okhttp 线程池_基于OkHttp实现Java多线程下载方案分析与实现

说明这篇文章主要是为了演示OkHttp和多线程的简单运用,利用多线程和HTTP断点续传的特性实现多线程下载。总体分为三种实现发难,并且实现了这三种方案。这里先说明,这只是一个Demo程序,为了快速实现功能,所以没有太多设计思想在里面,很多异常情况也没有考虑。所以,不喜勿喷,你如果觉得应该怎样,而不是我这样,那你自己去实现好了。当然,如果对我的方案,或实现上面有更好的想法,欢迎讨论。多线程下载方案分...

weixin_36168629的博客 990

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

揭秘Seal极速下载:aria2c多线程任务分配算法全解析

你还在为Android视频下载速度慢而烦恼吗?想知道Seal如何实现比普通下载工具快较多速度的?本文将深入解析Seal中基于aria2c的多线程任务分配算法,带你了解视频分段下载的核心技术,看完你将掌握:Seal下载引擎的工作原理、aria2c分段策略的优势、多线程任务调度机制以及实际操作中的优化技巧。 ## 为什么选择aria2c作为Seal的下载引擎 Seal作为一款基于yt-dlp的An...

gitblog_01190的博客 979

推荐开源项目:Proxyee-Down - 强大的HTTP下载工具

推荐开源项目:Proxyee-Down - 强大的HTTP下载工具 项目地址:https://gitcode.com/gh_mirrors/prox/proxyee-down 项目简介 是一个基于Java开发的开放源代码项目,它允许用户通过自定义HTTP代理服务器实现文件的多线程下载,尤其适用于大文件和网页抓取。该项目旨在提供一种灵活、可扩展的方式来控制和优化下载过程,赋予用户更多的操作自由度。 ...

gitblog_00063的博客 1096

Java并发编程框架之综合案例——文件上传下载平台(三)

它不仅能够加深对多线程的理解,还可以探索一些高级特性如Fork/Join框架的应用。此类项目通常涉及到长时间运行的任务处理,并且需要确保任务之间不会相互干扰;同时还需要考虑到系统的可扩展性和容错性,例如当某个节点失败时其他节点应该能够接管未完成的工作。

物联网工程专业 - 软硬兼修 1479

ForkJoin框架的分而治之

分而治之的思想不陌生了,归并排序用到,即把待排序列递归地等分成两个子序列,并排序,这样在不停递归等分,排序归并过程中,会得到若干个有序序列,因为递归过程是等分成左右序列嘛,所以最后会得到两个有序的序列,再做一次归并操作即可。外部排序中也用到,现在在多线程中也有,在多线程中分而治之思想有基于数据的分割和基于任务的分割。拿基于数据的分割来说,例如对于一个大文件的下载,使用多个线程分别下载一个大文件的不...

大力海棠的博客 406
上一篇: java实现高效文件下载
下一篇: Java集合知识点总结——ArrayList和LinkList
Mr.姚先森
博客等级 码龄11年 26粉丝 32原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值