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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章