在Android中实现大文件的分片上传 断点续传
前言
最近在公司的开发任务中,有一个大文件需要分片上传的功能要求,由于之前没有做过这个功能,看了一下网上的博客,有看到生成一些小文件再上传的,感觉不是很好,所以在这记录一下最后的代码,希望能跟大家交流一下
代码
1.将需要上传的文件分片处理
分块方法
/**
* @param offset 偏移量
* @param file 分块文件
* @param blockSize 每块的大小
* @return 这一片的数据
*/
private byte[] getBlock(long offset, File file, int blockSize) {
byte[] result = new byte[blockSize];
try (RandomAccessFile accessFile = new RandomAccessFile(file, "r")) {
accessFile.seek(offset);
int readSize = accessFile.read(result);
if (readSize == -1) {
return null;
} else if (readSize == blockSize) {
return result;
} else {
byte[] byteArray = new byte[readSize];
System.arraycopy(result, 0, byteArray, 0, readSize);
return byteArray;
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
2.将分片数据上传
private void uploadFile(String filePath){
File file = new File(filePath);
if (file .exists()){
//md5值是后台接口需要
String md5 = getFileMD5(file );
//计算文件分片的总块数
long totalBlock = sourceFile.length() / PART_SIZE + (sourceFile.length() % PART_SIZE > 0 ? 1 : 0);
//不要怀疑Math.max(totalBlock,1)的用法,因为我要上传0长度但有内容的文件(真的有!)
uploadFile(filePath,file.getName(),file.length(),Math.max(totalBlock,1),1,md5);
} else {
//不存在则回调错误方法
msg.append("file not exists");
onError();
}
}
private void uploadFile(String filePath, String fileName, long totalSize, long totalBlock, int currentBlock, String md5){
File file = new File(filePath);
byte[] fileStream = getBlock((currentBlock-1)*PART_SIZE,file,PART_SIZE);
if (fileStream == null) {
msg.append("getBlock error");
onError();
return;
}
MultipartBody.Builder builder = new MultipartBody.Builder();
builder.setType(MultipartBody.FORM);
builder.addFormDataPart("totalSize", String.valueOf(totalSize))
.addFormDataPart("totalBlock", String.valueOf(totalBlock))
.addFormDataPart("currentBlock", String.valueOf(currentBlock))
.addFormDataPart("md5",md5)
.addFormDataPart("type","file");
RequestBody body = RequestBody.create(MultipartBody.FORM, fileStream);
builder.addFormDataPart("file", fileName, body);
RetrofitUtil.upload(token,builder.build()).enqueue(new Callback<UploadSuccess>() {
@Override
public void onResponse(Call<UploadSuccess> call, Response<UploadSuccess> response) {
UploadSuccess success = response.body();
if (success != null) {
if (success.isStatus()) {
if (currentBlock == totalBlock) {
onSuccess();
} else {
// 在回调里面上传下一分片,比直接循环更加友好
uploadFile(filePath,fileName,totalSize,totalBlock,currentBlock+1,md5,callBack);
}
} else {
msg.append(success.getMsg());
onError();
}
}
}
@Override
public void onFailure(Call<UploadSuccess> call, Throwable t) {
msg.append(t.getMessage());
t.printStackTrace();
onError();
}
});
}
3.Retrofit上传接口
@POST("api/upload")
Call<UploadSuccess> upload(@Header("Authorization")String token, @Body RequestBody requestBody);
总结
我不知道这些代码有没有更好的写法,有的话在评论下面告诉我吧,也希望能给没做过分片上传文件的伙伴一个思路,如果需要实现断点续传的话,只需要记录哪些分片已经上传成功,在恢复上传的时候上传之后的分片,最终后台就可以合并成完整的文件了,加油工程师们!觉得不错的话就点个赞吧本文链接https://blog.csdn.net/weixin_44337681/article/details/112900048
未经允许,请勿转载!