OkHttp 中实现断点续传 demo

news2025/6/12 22:59:41

在 OkHttp 中实现断点续传主要通过以下步骤完成,核心是利用 HTTP 协议的 Range 请求头指定下载范围:

实现原理

  1. Range 请求头:向服务器请求文件的特定字节范围(如 Range: bytes=1024-

  2. 本地文件记录:保存已下载的字节位置

  3. 206 状态码处理:服务器返回部分内容(HTTP 206 Partial Content)

  4. 文件追加写入:从上次中断的位置继续写入文件

完整实现代码(Kotlin/Java)

kotlin

import okhttp3.*
import java.io.File
import java.io.IOException
import java.io.RandomAccessFile

class ResumeDownloader(
    private val client: OkHttpClient = OkHttpClient()
) {
    fun download(url: String, file: File, listener: ProgressListener? = null) {
        // 1. 获取已下载字节数
        val downloadedBytes = if (file.exists()) file.length() else 0L

        // 2. 创建带Range头的请求
        val request = Request.Builder()
            .url(url)
            .header("Range", "bytes=$downloadedBytes-")
            .build()

        client.newCall(request).enqueue(object : Callback {
            override fun onFailure(call: Call, e: IOException) {
                listener?.onError(e)
            }

            override fun onResponse(call: Call, response: Response) {
                if (!response.isSuccessful) {
                    listener?.onError(IOException("Unexpected code: ${response.code}"))
                    return
                }

                // 3. 检查服务器是否支持断点续传
                val isResumeSupported = response.code == 206 // Partial Content
                val totalBytes = response.header("Content-Length")?.toLongOrNull() ?: -1L
                val finalTotalBytes = if (isResumeSupported) {
                    downloadedBytes + (totalBytes)
                } else {
                    totalBytes
                }

                // 4. 处理响应体
                response.body?.use { body ->
                    RandomAccessFile(file, "rw").use { output ->
                        // 移动到文件末尾追加
                        output.seek(downloadedBytes)

                        val input = body.byteStream()
                        val buffer = ByteArray(8192)
                        var bytesRead: Int
                        var progress = downloadedBytes

                        // 5. 写入文件
                        while (input.read(buffer).also { bytesRead = it } != -1) {
                            output.write(buffer, 0, bytesRead)
                            progress += bytesRead
                            // 更新进度
                            listener?.onProgress(progress, finalTotalBytes)
                        }
                        listener?.onComplete(file)
                    }
                }
            }
        })
    }

    interface ProgressListener {
        fun onProgress(currentBytes: Long, totalBytes: Long)
        fun onComplete(file: File)
        fun onError(e: Exception)
    }
}

Java 版本核心代码

java

// 创建带Range头的请求
long downloadedBytes = file.length();
Request request = new Request.Builder()
    .url(url)
    .addHeader("Range", "bytes=" + downloadedBytes + "-")
    .build();

// 处理响应
try (Response response = client.newCall(request).execute()) {
    if (response.code() == 206) { // Partial Content
        try (RandomAccessFile output = new RandomAccessFile(file, "rw");
             InputStream input = response.body().byteStream()) {
            
            output.seek(downloadedBytes);
            byte[] buffer = new byte[8192];
            int bytesRead;
            while ((bytesRead = input.read(buffer)) != -1) {
                output.write(buffer, 0, bytesRead);
            }
        }
    }
}

关键注意事项

  1. 服务器支持检查

    • 成功时返回 HTTP 206(部分内容)

    • 失败时返回 200(完整文件)或 416(范围请求错误)

    • 响应头需包含 Accept-Ranges: bytes

  2. 文件处理

    • 使用 RandomAccessFile 实现文件随机访问

    • 通过 seek() 定位到文件末尾

    • 避免覆盖已下载内容

  3. 进度跟踪

    • 总大小 = 已下载大小 + Content-Length

    • 实时计算:currentBytes += bytesRead

  4. 异常处理

    • 网络中断时保存当前进度

    • 重新下载时使用最新文件长度

增强功能建议

  1. 进度持久化:使用数据库记录下载状态

  2. 暂停/恢复:暴露下载控制接口

  3. 多线程下载:分割文件范围并行下载(需服务器支持)

  4. 完整性校验:下载完成后验证文件 MD5/SHA1

示例用法:

kotlin

val downloader = ResumeDownloader()
val file = File(context.filesDir, "largefile.zip")

downloader.download("https://example.com/largefile.zip", file,
    object : ResumeDownloader.ProgressListener {
        override fun onProgress(current: Long, total: Long) {
            val percent = (current * 100 / total).toInt()
            updateProgressBar(percent)
        }
        
        override fun onComplete(file: File) {
            showToast("下载完成")
        }
        
        override fun onError(e: Exception) {
            showError(e.message)
        }
    }
)

通过此实现,OkHttp 可在网络中断后自动从断点恢复下载,大幅提升大文件下载体验。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2407690.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

页面渲染流程与性能优化

页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…

srs linux

下载编译运行 git clone https:///ossrs/srs.git ./configure --h265on make 编译完成后即可启动SRS # 启动 ./objs/srs -c conf/srs.conf # 查看日志 tail -n 30 -f ./objs/srs.log 开放端口 默认RTMP接收推流端口是1935,SRS管理页面端口是8080,可…

2021-03-15 iview一些问题

1.iview 在使用tree组件时,发现没有set类的方法,只有get,那么要改变tree值,只能遍历treeData,递归修改treeData的checked,发现无法更改,原因在于check模式下,子元素的勾选状态跟父节…

React19源码系列之 事件插件系统

事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…

ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放

简介 前面两期文章我们介绍了I2S的读取和写入,一个是通过INMP441麦克风模块采集音频,一个是通过PCM5102A模块播放音频,那如果我们将两者结合起来,将麦克风采集到的音频通过PCM5102A播放,是不是就可以做一个扩音器了呢…

Nuxt.js 中的路由配置详解

Nuxt.js 通过其内置的路由系统简化了应用的路由配置,使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…

高等数学(下)题型笔记(八)空间解析几何与向量代数

目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…

屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!

5月28日,中天合创屋面分布式光伏发电项目顺利并网发电,该项目位于内蒙古自治区鄂尔多斯市乌审旗,项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站,总装机容量为9.96MWp。 项目投运后,每年可节约标煤3670…

P3 QT项目----记事本(3.8)

3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…

Cinnamon修改面板小工具图标

Cinnamon开始菜单-CSDN博客 设置模块都是做好的&#xff0c;比GNOME简单得多&#xff01; 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…

华为OD机试-食堂供餐-二分法

import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…

跨链模式:多链互操作架构与性能扩展方案

跨链模式&#xff1a;多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈&#xff1a;模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展&#xff08;H2Cross架构&#xff09;&#xff1a; 适配层&#xf…

MODBUS TCP转CANopen 技术赋能高效协同作业

在现代工业自动化领域&#xff0c;MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步&#xff0c;这两种通讯协议也正在被逐步融合&#xff0c;形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…

Keil 中设置 STM32 Flash 和 RAM 地址详解

文章目录 Keil 中设置 STM32 Flash 和 RAM 地址详解一、Flash 和 RAM 配置界面(Target 选项卡)1. IROM1(用于配置 Flash)2. IRAM1(用于配置 RAM)二、链接器设置界面(Linker 选项卡)1. 勾选“Use Memory Layout from Target Dialog”2. 查看链接器参数(如果没有勾选上面…

如何将联系人从 iPhone 转移到 Android

从 iPhone 换到 Android 手机时&#xff0c;你可能需要保留重要的数据&#xff0c;例如通讯录。好在&#xff0c;将通讯录从 iPhone 转移到 Android 手机非常简单&#xff0c;你可以从本文中学习 6 种可靠的方法&#xff0c;确保随时保持连接&#xff0c;不错过任何信息。 第 1…

苍穹外卖--缓存菜品

1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得&#xff0c;如果用户端访问量比较大&#xff0c;数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据&#xff0c;减少数据库查询操作。 缓存逻辑分析&#xff1a; ①每个分类下的菜品保持一份缓存数据…

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; 目前2025年06月05日更新到&#xff1a; AI炼丹日志-28 - Aud…

【2025年】解决Burpsuite抓不到https包的问题

环境&#xff1a;windows11 burpsuite:2025.5 在抓取https网站时&#xff0c;burpsuite抓取不到https数据包&#xff0c;只显示&#xff1a; 解决该问题只需如下三个步骤&#xff1a; 1、浏览器中访问 http://burp 2、下载 CA certificate 证书 3、在设置--隐私与安全--…

DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI

前一阵子在百度 AI 开发者大会上&#xff0c;看到基于小智 AI DIY 玩具的演示&#xff0c;感觉有点意思&#xff0c;想着自己也来试试。 如果只是想烧录现成的固件&#xff0c;乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外&#xff0c;还提供了基于网页版的 ESP LA…