Android 文件分片/断点上传原理解析

分片/断点上传
分片上传功能支持将一个文件切割为一系列特定大小的小数据片,分别将这些小数据片分别上传到服务端,全部上传完后再在服务端将这些小数据片合并成为一个资源。
我们可以把一个文件理解成块(block), 然后一个文件可以分成多个片(chunk).那么一个文件资源则是一个和多个片组成.
块是服务器持久存储数据单位(可以理解一个完整的文件)
片是上传文件临时的存储(可以和服务器约定周期时间未能合并成块的文件进行清除)
基本流程
第一步:调用检测接口,以filename为参数,目的:检测当前文件服务器内是否存在(两种情况1:文件上传完成2:文件上传部分(多少片), 根据上传情况后台会给你响应:上传完成返回1,其他情况会返回上传的片)
第二步:将准备上传的文件进行分片,例如:我们将一个12.5m的大小的的文件分若干片(一片5m)不足5m的也是一片,
       带文件上传完成后服务器将上传的片进行合并成完整文件
上传的核心代码(基于okhttp上传)
 //上传写在线程里面
 @Override
    public void run() {
        try {
            int blockLength = 1024 * 1024;//一块以为1m
            file = new File(fileName);
            long tsize = file.length();
            //文件越大,等越长的时间
            int wTime = (int)(tsize/1000/1000)*150+5000;
            try{
                //休眠3秒,确保操作系统的文件写入成功
                Thread.sleep(wTime);
            }catch(Exception e){}

            String debugstr = "";
            if (tsize!=file.length()){
                debugstr = "文件上传时发现文件大小的变动,从"+tsize+"变成"+file.length();
            }
            if (file.length() % blockLength == 0) {
                chuncks = (int) file.length() / blockLength;
            } else {
                chuncks = (int) file.length() / blockLength + 1;

            }
            //String md5str = MD5Utils.getFileMD5String(new File(file.getPath()));//超大文件可能会导致内存问题
            while (
                    chunck <= chuncks
                            &&uploadStatus!= UploadStatus.UPLOAD_STATUS_PAUSE
                            &&uploadStatus!= UploadStatus.UPLOAD_STATUS_ERROR)
            {

                uploadStatus = UploadStatus.UPLOAD_STATUS_UPLOADING;
                final byte[] mBlock = FileUtils.getBlock((chunck - 1) * blockLength, file, blockLength);

                String md5 = MD5Utils.getMD5String(mBlock);//MD5加密将用来验证上传的文件是否和服务器接收的一致如果不一致重新上传  
                Map<String, String> params = new HashMap<String, String>();
                params.put("name", file.getName());//fileName
                params.put("chunks", chuncks + "");//一个文件共被分成了多少片
                params.put("chunk", chunck + "");//上传到的片数
                params.put("filelength", file.length() + "");//文件的总大小,服务器校验大小是否一致
                params.put("md5str", md5);//md5加密参数
                params.put("debugstr", debugstr);//测试debug
                MultipartBody.Builder builder = new MultipartBody.Builder()
                        .setType(MultipartBody.FORM);
                addParams(builder, params);
                RequestBody requestBody = RequestBody.create(MEDIA_TYPE_MARKDOWN, mBlock);
                builder.addFormDataPart("mFile", file.getName(), requestBody);//filename
                Log.i("onUploadSuccessurl",url);
                Request request = new Request.Builder()
                        .url(url)
                        .post(builder.build())
                        .build();
                Response response = null;
                response = mClient.newCall(request).execute();

                if (response.isSuccessful()) {
                    String string = response.body().string();
                    Log.i("isEmptyisEmpty",string);

                    try {
                        JSONObject jsonObject  = new JSONObject(string);
                        if (jsonObject.has("url")) {
                            String url = jsonObject.getString("url");
                            onCallBack(url, file_id);
                        }

                        onCallBack(file_id);

                        if(jsonObject.has("status")){
                            //如果服务器返回失败,应该要处理
                            boolean status = jsonObject.getBoolean("status");
                            if (status ==false){
                                Log.e("return", status+"");
                                uploadStatus = UploadStatus.UPLOAD_STATUS_ERROR;
                            }

                        }

                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                    //onCallBack();
                    chunck++;
                   /* if (chunck <= chuncks) {
                         run();
                    }*/
                }
                else
                {
                    uploadStatus = UploadStatus.UPLOAD_STATUS_ERROR;
                    onCallBack();
                }

            }
        } catch (IOException e) {
            uploadStatus = UploadStatus.UPLOAD_STATUS_ERROR;
            onCallBack();
            e.printStackTrace();
        }
    }
 
测试结果

在这里插入图片描述
前三个代表没有文件没有上传完整,最后一个是服务器端将完成文件合成成功返回的结果

这个是一个Android客户端分片上传文件的核心记录

对你有帮助记得点赞❥(^_-)
我的开源网络框架---------点击移步github

发布了9 篇原创文章 · 获赞 5 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/beahug/article/details/105106679