Java实现http请求文件流对带宽限速获取md5值

 更新时间:2025年02月28日 09:45:14   作者:曲奇hmb  
文章介绍了如何在进行HTTP请求下载大数据时处理带宽限制和并发问题,通过使用缓冲区和限速逻辑,可以有效控制下载速度,避免掉包和数据丢失,核心公式基于带宽和已下载字节数计算预期耗时,并通过Thread.sleep()进行动态休眠补偿,感兴趣的朋友一起看看吧

场景:

当进行http请求获取大数据的情况,例如下载视频图片的情况,特别是云服务器会有带宽限制,超出带宽会出现掉包丢数据的情况,例如:云服务器限制25m/s的速度,当一个视频下载超过25m/s的速度的时候就会导致掉包,除了限速还需要注意下并发问题,多个线程同时下载也会超出带宽限制,可实现该代码并设置单独的线程池,控制同时并发的线程数来解决带宽问题.

逻辑:

我们可以使用一个缓冲区,每次从输入流读取数据后,先将写入文件的同时更新MD5,这样更高效,因为只需要处理一次数据。这样就不会增加额外的读取次数,避免影响性能。然后,带宽限流的逻辑需要确保在限流的同时处理这两个操作。每次读取数据块后,会计算总字节数和时间,判断是否需要暂停(使用Thread.sleep())。计算MD5的消耗应该相对较小,主要的时间还是在网络读取和文件写入上。

1. 核心公式

限速逻辑基于以下公式实现:

预期耗时(ms)=已下载总字节数×1000最大允许带宽(B/s)预期耗时(ms)=最大允许带宽(B/s)已下载总字节数×1000​

其中 MAX_BPS = NMB/s = N × 1024 × 1024 B/s

2. 控制逻辑分步说明

步骤代码片段说明
1. 记录开始时间long startTime = System.currentTimeMillis();下载任务启动时记录初始时间戳
2. 累计下载量totalBytes += bytesRead;每次读取数据块后更新总字节数
3. 计算理论耗时expectedTime = (totalBytes * 1000) / MAX_BPS根据当前下载量计算理论应耗时
4. 对比实际耗时elapsed = now - startTime获取实际已耗时
5. 动态休眠补偿Thread.sleep(expectedTime - elapsed)强制等待至理论时间线

流程:

1. 打开网络连接,获取输入流。

2. 创建文件输出流和MessageDigest实例。

3. 循环读取数据到缓冲区,每次读取后写入文件,更新MD5(MD5可以边读取文件边计算,防止整个文件读取完再计算导致的内存压力),并进行限流计算。

4. 下载完成后,关闭流,并输出MD5结果。

实现:

 
public static String getMd5(String url, String type) {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        final long MAX_BPS = 2 * 1024 * 1024; // 200Mbps = 25MB/s
        MessageDigest md;
        // 创建时间格式化器(线程安全)
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
        try {
            md = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("MD5 algorithm not found", e);
        }
        try (CloseableHttpResponse response = httpClient.execute(new HttpGet(url))) {
            HttpEntity entity = response.getEntity();
            if (entity == null) {
                return "";
            }
            // 记录开始时间
            long startTime = System.currentTimeMillis();
            try (InputStream in = entity.getContent()) {
                byte[] buffer = new byte[8192];
                int bytesRead;
                long totalBytes = 0;
                while ((bytesRead = in.read(buffer)) != -1) {
                    md.update(buffer, 0, bytesRead);
                    totalBytes += bytesRead;
                    // 动态限速逻辑
                    long elapsed = System.currentTimeMillis() - startTime;
                    long expectedTime = (totalBytes * 1000) / MAX_BPS;
                    if (elapsed < expectedTime) {
                        Thread.sleep(expectedTime - elapsed);
                    }
                }
                // 计算最终统计信息
                long endTime = System.currentTimeMillis();
                double timeCost = DoubleUtils.formatDouble((endTime - startTime) / 1000.0);
                String sizeMB = String.format("%.3f", DoubleUtils.formatDouble(totalBytes / (1024.0 * 1024)));
                // 生成MD5
                String md5 = DatatypeConverter.printHexBinary(md.digest()).toLowerCase();
                // 完整日志输出
                log.info("下载完成 | 类型: {} | MD5: {} | 大小: {}MB | 耗时: {}s",
                        type, md5, sizeMB, timeCost);
                return md5;
            }
        } catch (Exception e) {
            // 记录异常发生时间
            String errorTime = LocalDateTime.now().format(formatter);
            log.error("下载失败 | 类型: {} | 错误时间: {} | 原因: {}",
                    type, errorTime, e.getMessage());
            return "";
        }finally {
            try {
                httpClient.close();
            }catch (Exception e) {
            }
        }
    }

到此这篇关于Java实现http请求文件流对带宽限速获取md5值的文章就介绍到这了,更多相关java带宽限速获取md5值内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • MyBatis Generator ORM层面的代码自动生成器(推荐)

    MyBatis Generator ORM层面的代码自动生成器(推荐)

    Mybatis Generator是一个专门为 MyBatis和 ibatis框架使用者提供的代码生成器,也可以快速的根据数据表生成对应的pojo类、Mapper接口、Mapper文件,甚至生成QBC风格的查询对象,这篇文章主要介绍了MyBatis Generator ORM层面的代码自动生成器,需要的朋友可以参考下
    2023-01-01
  • 最全总结SpringBean的作用域管理

    最全总结SpringBean的作用域管理

    今天给大家详细总结了SpringBean的作用域管理,文中有非常详细的图文介绍以及代码示例,对正在学习java的小伙伴们还很有帮助,需要的朋友可以参考下
    2021-05-05
  • 10k+点赞的 SpringBoot 后台管理系统教程详解

    10k+点赞的 SpringBoot 后台管理系统教程详解

    这篇文章主要介绍了10k+点赞的 SpringBoot 后台管理系统教程详解,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-01-01
  • SpringCloud-Gateway转发WebSocket失败问题及解决

    SpringCloud-Gateway转发WebSocket失败问题及解决

    这篇文章主要介绍了SpringCloud-Gateway转发WebSocket失败问题及解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-09-09
  • 适用于Java初学者的学习路线图

    适用于Java初学者的学习路线图

    这篇文章主要介绍了学习Java的路线图的五个必经阶段,还有一些作者的想法分享给大家,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-09-09
  • 兼容Spring Boot 1.x和2.x配置类参数绑定的工具类SpringBootBindUtil

    兼容Spring Boot 1.x和2.x配置类参数绑定的工具类SpringBootBindUtil

    今天小编就为大家分享一篇关于兼容Spring Boot 1.x和2.x配置类参数绑定的工具类SpringBootBindUtil,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2018-12-12
  • 4个Java8中你需要知道的函数式接口分享

    4个Java8中你需要知道的函数式接口分享

    Java 8 中提供了许多函数式接口,包括Function、Consumer、Supplier、Predicate 等等。本文主要来和大家介绍一下它们的具体使用,需要的可以参考一下
    2023-04-04
  • 基于java springboot + mybatis实现电影售票管理系统

    基于java springboot + mybatis实现电影售票管理系统

    这篇文章主要介绍了基于java springboot + mybatis实现的完整电影售票管理系统基于java springboot + mybatis,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-08-08
  • SpringBoot整合Security实现权限控制框架(案例详解)

    SpringBoot整合Security实现权限控制框架(案例详解)

    Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框,是一个重量级的安全管理框架,本文给大家介绍的非常详细,需要的朋友参考下吧
    2021-08-08
  • JavaWEB中Servlet的生命周期详解

    JavaWEB中Servlet的生命周期详解

    大家好,本篇文章主要讲的是JavaWEB中Servlet的生命周期详解,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下
    2022-01-01

最新评论