okhttp断点续传

使用 OkHttp 实现断点续传,关键是通过设置 Range 请求头向服务器请求文件的部分内容。下面是详细的实现步骤和示例代码。

步骤

  1. 获取文件的总大小:在开始下载前,通常需要知道文件的总大小,可以通过发送一个初始请求来获取。
  2. 记录已下载字节数:记录已下载的字节数,确保在下载中断后能够继续。
  3. 分块下载 :每次发送一个 Range 请求,告诉服务器从哪个字节位置开始传输文件,并获取相应的字节块。
  4. 处理中断续传:如果下载过程中中断,可以通过记录的已下载字节数,从上次停止的位置继续下载。

代码实现

1. 添加 OkHttp 库

build.gradle 中添加 OkHttp 的依赖:

java 复制代码
dependencies {
    implementation("com.squareup.okhttp3:okhttp:4.9.0")
}
2. 定义下载函数

使用 Range 请求头来获取文件的部分内容。

java 复制代码
import okhttp3.*;
import java.io.*;
import java.util.concurrent.TimeUnit;

public class FileDownloader {
    private static final String FILE_URL = "http://example.com/largefile.zip";  // 文件 URL
    private static final String FILE_PATH = "your/local/path/largefile.zip";    // 保存路径
    private static final long CHUNK_SIZE = 1024 * 1024;  // 每次下载 1MB

    private OkHttpClient client;
    private long downloadedBytes = 0;  // 已下载字节数

    public FileDownloader() {
        client = new OkHttpClient.Builder()
                .connectTimeout(30, TimeUnit.SECONDS)
                .readTimeout(30, TimeUnit.SECONDS)
                .build();
    }

    // 获取已下载的字节数
    private long getDownloadedBytes() {
        File file = new File(FILE_PATH);
        if (file.exists()) {
            return file.length();
        }
        return 0;
    }

    // 保存下载的数据到本地文件
    private void saveToFile(byte[] data) {
        try (FileOutputStream fos = new FileOutputStream(FILE_PATH, true)) {  // 以追加模式写入文件
            fos.write(data);
            fos.flush();
            downloadedBytes += data.length;  // 更新已下载字节数
            System.out.println("Downloaded " + downloadedBytes + " bytes.");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // 下载文件块
    private void downloadFileChunk(long startByte, long endByte) {
        Request request = new Request.Builder()
                .url(FILE_URL)
                .header("Range", "bytes=" + startByte + "-" + endByte)  // 设定下载范围
                .build();

        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                e.printStackTrace();
                System.out.println("Download failed");
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if (response.isSuccessful()) {
                    byte[] data = response.body().bytes();
                    saveToFile(data);  // 保存文件
                    if (downloadedBytes < response.body().contentLength()) {
                        // 继续下载下一个部分
                        long nextStartByte = downloadedBytes;
                        long nextEndByte = Math.min(nextStartByte + CHUNK_SIZE - 1, response.body().contentLength());
                        downloadFileChunk(nextStartByte, nextEndByte);  // 递归下载下一个部分
                    } else {
                        System.out.println("Download completed");
                    }
                } else {
                    System.out.println("Server response failed: " + response.code());
                }
            }
        });
    }

    // 启动下载任务
    public void startDownload() {
        downloadedBytes = getDownloadedBytes();  // 获取当前已下载的字节数
        long totalFileSize = getFileSize();  // 获取文件的总大小
        long startByte = downloadedBytes;
        long endByte = Math.min(startByte + CHUNK_SIZE - 1, totalFileSize);

        downloadFileChunk(startByte, endByte);  // 开始下载文件
    }

    // 获取文件总大小(可以通过 HEAD 请求或事先知道文件的大小)
    private long getFileSize() {
        Request request = new Request.Builder()
                .url(FILE_URL)
                .head()  // HEAD 请求
                .build();

        try (Response response = client.newCall(request).execute()) {
            if (response.isSuccessful()) {
                return response.body().contentLength();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        return 0;
    }
}

解释

  1. 获取已下载的字节数

    • 通过 getDownloadedBytes() 方法来检查本地文件是否已经部分下载。如果文件已存在,返回已下载的字节数。
  2. 分块下载

    • 每次下载 1MB(CHUNK_SIZE 设置为 1MB),通过 Range 请求头向服务器请求文件的指定字节范围(例如 Range: bytes=0-1048575 请求从 0 到 1MB 的文件)。
  3. 保存文件并更新进度

    • 下载的文件块会通过 saveToFile() 方法保存到本地。如果下载的文件还没有完成,则继续请求下一个块。下载完成时,会打印 Download completed
  4. 获取文件总大小

    • 使用 HEAD 请求获取文件的大小,确保可以计算分块的范围。如果你已知文件的总大小,也可以省略这一步。
  5. 递归下载

    • 下载完成一个块后,递归调用 downloadFileChunk() 方法下载下一个块,直到文件完全下载。
相关推荐
whltaoin4 天前
Java 网络请求 Jar 包选型指南:从基础到实战
java·http·okhttp·网络请求·retrofit
华农第一蒟蒻5 天前
谈谈跨域问题
java·后端·nginx·安全·okhttp·c5全栈
一直向钱6 天前
android 基于okhttp的socket封装
android·okhttp
linuxxx1106 天前
ajax回调钩子的使用简介
okhttp
一直向钱8 天前
android 基于okhttp 封装一个websocket管理模块,方便开发和使用
android·websocket·okhttp
linuxxx1109 天前
ajax() 回调函数参数详解
前端·ajax·okhttp
linuxxx11011 天前
ajax与jQuery是什么关系?
ajax·okhttp·jquery
耀耀_很无聊13 天前
12_OkHttp初体验
okhttp
heeheeai13 天前
okhttp使用指南
okhttp·kotlin·教程
啦工作呢15 天前
ES6 promise-try-catch-模块化开发
android·okhttp