OkHttp 断点上传的“基操”,真还有人不知道?

经常会有同学问:文件的断点上传如何实现?

断点上传/下载,这是在客户端经常遇到的场景,当我们需要上传或下载一个大文件时,都会考虑使用断点续传的方式。

断点上传相较于断点下载来说,最大的区别就在于断点位置的记录,上传记录在服务端,下载记录在客户端,因此,客户端需要在上传前,通过接口去拿到文件的断点位置,然后在上传时,将文件输入流跳转到断点位置

2、准备工作

======

对于文件上传,其实就是打开文件的输入流,不停的读取数据到byte数组中,随后写出到服务端;那客户端要做的就是跳过已经上传的部分,也就是直接跳到断点位置,这样就可以从断点位置去读取数据,也就达到了断点上传的目的。

伪代码如下:

String filePath = “…”;

long skipSize = 100; //假设断点位置是 100 byte

InputStream input = input = new FileInputStream(filePath);

input.skip(skipSize) //跳转到断点位置

然而,OkHttp并没有直接提供设置断点的方法,所以需要客户端自定义RequestBody,取名为FileRequestBody,如下:

//为简化阅读,已省略部分代码

public class FileRequestBody extends RequestBody {

private final File file;

private final long skipSize; //断点位置

private final MediaType mediaType;

public FileRequestBody(File file, long skipSize, @Nullable MediaType mediaType) {

this.file = file;

this.skipSize = skipSize;

this.mediaType = mediaType;

}

@Override

public long contentLength() throws IOException {

return file.length() - skipSize;

}

@Override

public void writeTo(@NotNull BufferedSink sink) throws IOException {

InputStream input = null;

Source source = null;

try {

input = new FileInputStream(file);

if (skipSize > 0) {

input.skip(skipSize); //跳到断点位置

}

source = Okio.source(input);

sink.writeAll(source);

} finally {

OkHttpCompat.closeQuietly(source, input);

}

}

}

为方便阅读,以上省略部分源码,FileRequestBody类完整源码

有了FileRequestBody类,我们只需要传入一个断点位置,剩下的工作就跟普通的文件上传一样。 接下来,直接进入代码实现。

3、代码实现

======

3.1 获取断点位置


首先,需要服务端提供一个接口,通过userId去查找该用户未上传完成的任务列表,代码如下:

RxHttp.get(“/…/getToUploadTask”)

.add(“userId”, “88888888”)

.asList()

.subscribe({

//成功回调,这里通过 it 拿到 List

}, {

//异常回调

});

其中ToUploadTask类如下:

//待上传任务

data class ToUploadTask(

val md5: String, //文件的md5,用于验证文件的唯一性

val filePath: String, //文件在客户端的绝对路径

val skipSize: Long = 0 //断点位置

)

注:md5、filePath 这两个参数需要客户端在文件上传时传递给服务端,用于对文件的校验,防止文件错乱

3.2 断点上传


有了待上传任务,客户端就可以执行断点上传操作,OkHttp代码如下:

fun uploadFile(uploadTask: ToUploadTask) {

//1.校验文件是否存在

val file = File(uploadTask.filePath)

if (!file.exists() && !file.isFile) return

//2.校验文件的 md5 值

val fileMd5 = FileUtils.getFileMD5ToString(file)

if (!fileMd5.equals(uploadTask.md5)) return

//3.构建请求体

val fileRequestBody = FileRequestBody(file, uploadTask.skipSize, BuildUtil.getMediaType(file.name))

val multipartBody = MultipartBody.Builder()

.addFormDataPart(“userId”, “88888888”)

.addFormDataPart(“md5”, fileMd5)

.addFormDataPart(“filePath”, file.absolutePath)

.addFormDataPart(“file”, file.name, fileRequestBody) //添加文件body

.build()

//4.构建请求

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

最后

说一千道一万,不如自己去行动。要想在移动互联网的下半场是自己占有一席之地,那就得从现在开始,从今天开始,马上严格要求自己,既重视业务实现能力,也重视基础和原理。基础夯实好了,高楼才能够平地而起,稳如泰山。

最后为了帮助大家深刻理解Android相关知识点的原理以及面试相关知识,这里放上相关的我搜集整理的24套腾讯、字节跳动、阿里、百度2020-2021面试真题解析,我把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包知识脉络 + 诸多细节

还有 高级架构技术进阶脑图、Android开发面试专题资料 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。

一线互联网面试专题

379页的Android进阶知识大全

379页的Android进阶知识大全

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门即可获取!

718)]

[外链图片转存中…(img-aRk7fm4s-1711868916718)]

[外链图片转存中…(img-1QkpjKYQ-1711868916718)]

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门即可获取!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值