经常会有同学问:文件的断点上传如何实现?
断点上传/下载,这是在客户端经常遇到的场景,当我们需要上传或下载一个大文件时,都会考虑使用断点续传的方式。
断点上传相较于断点下载来说,最大的区别就在于断点位置的记录,上传记录在服务端,下载记录在客户端,因此,客户端需要在上传前,通过接口去拿到文件的断点位置,然后在上传时,将文件输入流跳转到断点位置
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移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)
最后
说一千道一万,不如自己去行动。要想在移动互联网的下半场是自己占有一席之地,那就得从现在开始,从今天开始,马上严格要求自己,既重视业务实现能力,也重视基础和原理。基础夯实好了,高楼才能够平地而起,稳如泰山。
最后为了帮助大家深刻理解Android相关知识点的原理以及面试相关知识,这里放上相关的我搜集整理的24套腾讯、字节跳动、阿里、百度2020-2021面试真题解析,我把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包知识脉络 + 诸多细节。
还有 高级架构技术进阶脑图、Android开发面试专题资料 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。
网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门即可获取!
718)]
[外链图片转存中…(img-aRk7fm4s-1711868916718)]
[外链图片转存中…(img-1QkpjKYQ-1711868916718)]
网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。