使用多线程实现文件的下载_多线程写同一个文件

使用多线程实现文件的下载_多线程写同一个文件首先,我们要下载一个文件,可以通过多线程的方式快速下载!!!多线程下载文件的步骤:1、首先要知道请求下载的服务器支持断点下载,即支持request头信息中的Range的设置2、然后通过对请求头设置httpRequest.setRequestProperty(“Range”,”bytes=”+startIndex+”-“+endIndex);3、然后获取整个文件的大小4、在……

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

首先,我们要下载一个文件,可以通过多线程的方式快速下载!!!

多线程下载文件的步骤:

1、首先要知道请求下载的服务器支持断点下载,即支持request头信息中的Range的设置

2、然后通过对请求头设置

httpConnection.setRequestProperty("Range","bytes="+startIndex+"-"+endIndex);

3、然后获取整个文件的大小

4、在本地创建一个一样大的文件,然后根据线程数进行分配startIndex和endIndex

5、线程下载的同时,使用RandomAccessFile对所下载的内容随机对应写入文件

这里要注意,你所访问的文件在服务器端必须吧能够返回Content-Length这个参数才行!!!

完整的示例代码:

package cn.ljxwtl.plugin.common.util;

import com.alibaba.fastjson.JSON;
import cn.ljxwtl.plugin.engine.EngineAssistant;
import org.apache.commons.io.IOUtils;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.RandomAccess;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @author: wtl
 * @License: (C) Copyright 2022, wtl Corporation Limited.
 * @Contact: 1050100468@qq.com
 * @Date: 2022/4/1 10:50
 * @Version: 1.0
 * @Description:
 */
public class DownloadFileUtil {

    public static void downloadFileWithMultiThread(String url,String filePath,Runnable runnable) throws Exception {
        List<long[]> perThreadDownloadFileOffset = getPerThreadDownloadFileOffset(url, 1024* 1024);
        ThreadPoolExecutor threadPoolExecutor = EngineAssistant.THREAD_POOL_EXECUTOR;

        int size = Objects.requireNonNull(perThreadDownloadFileOffset).size();

        CyclicBarrier cyclicBarrier = new CyclicBarrier(size, ()->{
            if (null != runnable){
                runnable.run();
            }
        });

        URL openUrl = new URL(url);

        for (int i = 0; i< size; i++){
            int finalI = i;
            new Thread(()->{
                try {
                    HttpURLConnection urlConnection = (HttpURLConnection) openUrl.openConnection();
                    urlConnection.setRequestProperty("Range","bytes="+perThreadDownloadFileOffset.get(finalI)[0]+"-"+perThreadDownloadFileOffset.get(finalI)[1]);
                    urlConnection.setDoInput(true);
                    BufferedInputStream bufferedInputStream = new BufferedInputStream(urlConnection.getInputStream());
                    int length = -1;
                    byte [] buffer = new byte[102400];
                    RandomAccessFile randomAccessFile = new RandomAccessFile(filePath,"rw");
                    System.out.println(perThreadDownloadFileOffset.get(finalI)[1] - perThreadDownloadFileOffset.get(finalI)[0]);
                    randomAccessFile.seek(perThreadDownloadFileOffset.get(finalI)[0]);
                    int perSize = 0;
                    while ((length = bufferedInputStream.read(buffer))!=-1){
                        randomAccessFile.write(buffer,0,length);
                        perSize +=length;
                    }
                    randomAccessFile.close();
                    System.out.println(perThreadDownloadFileOffset.get(finalI)[0] + "------------------" +(perThreadDownloadFileOffset.get(finalI)[0] +  perSize));
                } catch (Exception e) {
                    e.printStackTrace();
                }
                finally {
                    try {
                        cyclicBarrier.await();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }

    }


    /**
     * 获取每个线程所需要的File的offset
     * @param url url地址
     * @param perThreadDealFileSize 每个线程处理的文件下载大小
     * @return List<int []>
     */
    private static List<long []> getPerThreadDownloadFileOffset(String url,long perThreadDealFileSize){
        URLConnection urlConnection = null;
        try {
            urlConnection = new URL(url).openConnection();
            long contentLengthLong = urlConnection.getContentLengthLong();
            List<long[]> threadOffsetDatas = new ArrayList<>();
            long size = (long) Math.ceil(contentLengthLong * 1.0 / perThreadDealFileSize);
            for (int i = 0; i < size; i++) {
                long start = i * perThreadDealFileSize;
                long end = (i + 1) * perThreadDealFileSize - 1;

                if (i == size - 1) {
                    start = i * perThreadDealFileSize;
                    end = contentLengthLong;
                }

                threadOffsetDatas.add(new long[]{start,end});
            }

            System.out.println(JSON.toJSONString(threadOffsetDatas));
            return threadOffsetDatas;
        }
        catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/195242.html原文链接:https://javaforall.net

(0)
上一篇 2025年10月21日 上午8:22
下一篇 2025年10月21日 上午9:01


相关推荐

  • JMeter实战(二) 运行原理

    JMeter实战(二) 运行原理

    2020年11月20日
    269
  • 简述controller,service,repository注解的用法(谈谈application.properties的作用)

    Spring2.5中除了提供@Component注释外,还定义了几个拥有特殊语义的注释,它们分别是:@Repository、@Service和@Controller。在目前的Spring版本中,这3个注释和@Component是等效的,但是从注释类的命名上,很容易看出这3个注释分别和持久层、业务层和控制层(Web层)相对应。1、@Component@Comp…

    2022年4月14日
    80
  • 车载以太网概述

    车载以太网概述1 什么是车载以太网 车载以太网是用于连接汽车内各种电气设备的一种物理网络 车载以太网的设计是为了满足车载环境中的一些特殊需求 例如 满足车载设备对于电气特性的要求 EMI RF 满足车载设备对高带宽 低延迟以及音视频同步等应用的要求 满足车载系统对网络管理的需求等 因此可以理解为 车载以太网在民用以太网协议的基础上 改变了物理接口的电气特性 并结合车载网络需求专门定制了一些新标准 针对车载

    2026年3月19日
    2
  • Dubbo常用协议之Dubbo协议与Hessian协议解析

    Dubbo常用协议之Dubbo协议与Hessian协议解析前言 Dubbo 允许配置多协议 在不同服务上支持不同协议或者同一服务上同时支持多种协议 不同服务在性能上适用不同协议进行传输 比如大数据用短连接协议 小数据大并发用长连接协议 Dubbo 协议 Dubbo 缺省协议采用单一长连接和 NIO 异步通讯 适合于小数据量大并发的服务调用 以及服务消费者机器数远大于服务提供者机器数的情况 反之 Dubbo 缺省协议不适合传送大数据量的服务 比如传文件 传视频等 除非请求量很低 Dubbo 协议能使用的传输方式 mina netty grizzyDubbo 协议能

    2026年3月16日
    2
  • CUDA编程之快速入门(CUDA10)

    CUDA编程cmake基本模板cmake版本与命令cmake版本之间会有命令差异,高版本中会舍弃一些低版本中的命令。而网上找到的大部分的cuda程序cmake文件都是基于低版本的,基本上都是有 add_cuda_executable这个命令的版本。而这个命令在高版本中丢弃了,所以要修改win10预览版系统中cmake出错的问题如果安装的是win10的预览版或者其他什么原因,如果出现报错:–SelectingWindowsSDKversion10.0.19041.0totarge

    2022年4月10日
    179
  • linux登录root用户密码_centos7找回root密码

    linux登录root用户密码_centos7找回root密码Linux操作系统中用户管理的相关操作、root密码的找回方式。

    2022年10月7日
    8

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号