Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  package com.qiniu.android.storage;
  
 
 import  org.apache.http.Header;
 import  org.apache.http.message.BasicHeader;
 import  org.json.JSONArray;
 import  org.json.JSONException;
 import  org.json.JSONObject;
 
 import java.io.File;
 import java.util.Map;
 
 import static java.lang.String.format;

分片上传 文档:分片上传

分片上传通过将一个文件分割为固定大小的块(4M),然后再将每个块分割为固定大小的片,每次 上传一个分片的内容,等待所有块的所有分片都上传完成之后,再将这些块拼接起来,构成一个 完整的文件。另外分片上传还支持纪录上传进度,如果本次上传被暂停,那么下次还可以从上次 上次完成的文件偏移位置,继续开始上传,这样就实现了断点续传功能。

分片上传在网络环境较差的情况下,可以有效地实现大文件的上传。

 
 final class ResumeUploader implements Runnable {
 
     private final int size;
     private final String key;
     private final UpCompletionHandler completionHandler;
     private final UploadOptions options;
     private final HttpManager httpManager;
     private final Configuration config;
     private final byte[] chunkBuffer;
     private final String[] contexts;
     private final Header[] headers;
     private final long modifyTime;
     private final String recorderKey;
     private RandomAccessFile file;
     private File f;
     private long crc32;
     private UpToken token;
     private boolean forceIp = false;
 
     ResumeUploader(HttpManager httpManagerConfiguration configFile fileString keyUpToken token,
                    UpCompletionHandler completionHandlerUploadOptions optionsString recorderKey) {
         this. = httpManager;
         this. = config;
         this. = file;
         this. = recorderKey;
         this. = (intfile.length();
         this. = key;
         this. = new Header[1];
         [0] = new BasicHeader("Authorization""UpToken " + token.token);
         this. = completionHandler;
         this. = options != null ? options : UploadOptions.defaultOptions();
          = new byte[config.chunkSize];
         long count = ( + . - 1) / .;
          = new String[(intcount];
          = .lastModified();
         this. = token;
     }
 
     public void run() {
         int offset = recoveryFromRecord();
         try {
              = new RandomAccessFile("r");
         } catch (FileNotFoundException e) {
             e.printStackTrace();
             .complete(, ResponseInfo.fileError(e), null);
             return;
         }
         nextTask(offset, 0, .);
     }

    
创建块,并上传第一个分片内容

Parameters:
host 上传主机
offset 本地文件偏移量
blockSize 分块的块大小
chunkSize 分片的片大小
progress 上传进度
_completionHandler 上传完成处理动作
 
     private void makeBlock(String hostint offsetint blockSizeint chunkSizeProgressHandler progress,
                            CompletionHandler _completionHandlerUpCancellationSignal c) {
        String url = format(."http://%s/mkblk/%d"hostblockSize);
        try {
            .seek(offset);
            .read(, 0, chunkSize);
        } catch (IOException e) {
            .complete(, ResponseInfo.fileError(e), null);
            return;
        }
        this. = Crc32.bytes(, 0, chunkSize);
        post(url, 0, chunkSizeprogress_completionHandlerc);
    }
    private void putChunk(String hostint offsetint chunkSizeString contextProgressHandler progress,
                          CompletionHandler _completionHandlerUpCancellationSignal c) {
        int chunkOffset = offset % .;
        String url = format(."http://%s:%d/bput/%s/%d"host.contextchunkOffset);
        try {
            .seek(offset);
            .read(, 0, chunkSize);
        } catch (IOException e) {
            .complete(, ResponseInfo.fileError(e), null);
            return;
        }
        this. = Crc32.bytes(, 0, chunkSize);
        post(url, 0, chunkSizeprogress_completionHandlerc);
    }
    private void makeFile(String hostCompletionHandler _completionHandlerUpCancellationSignal c) {
        String mime = format(."/mimeType/%s", UrlSafeBase64.encodeToString(.));
        String keyStr = "";
        if ( != null) {
            keyStr = format("/key/%s", UrlSafeBase64.encodeToString());
        }
        String paramStr = "";
        if (..size() != 0) {
            String str[] = new String[..size()];
            int j = 0;
            for (Map.Entry<StringStringi : ..entrySet()) {
                str[j++] = format(."%s/%s"i.getKey(), UrlSafeBase64.encodeToString(i.getValue()));
            }
            paramStr = "/" + StringUtils.join(str"/");
        }
        String url = format(."http://%s/mkfile/%d%s%s%s"hostmimekeyStrparamStr);
        String bodyStr = StringUtils.join(",");
        byte[] data = bodyStr.getBytes();
        post(urldata, 0, data.lengthnull_completionHandlerc);
    }
    private void post(String urlbyte[] dataint offsetint sizeProgressHandler progress,
                      CompletionHandler completionUpCancellationSignal c) {
        .postData(urldataoffsetsizeprogresscompletionc);
    }
    private int calcPutSize(int offset) {
        int left =  - offset;
        return left < . ? left : .;
    }
    private int calcBlockSize(int offset) {
        int left =  - offset;
        return left < . ? left : .;
    }
    private boolean isCancelled() {
        return ..isCancelled();
    }
    private void nextTask(final int offsetfinal int retriedfinal String host) {
        if (offset == ) {
            CompletionHandler complete = new CompletionHandler() {
                @Override
                public void complete(ResponseInfo info, JSONObject response) {
                    if (info.isOK()) {
                        removeRecord();
                        ..progress(, 1.0);
                        .complete(inforesponse);
                        return;
                    }
                    if(isCancelled()){
                        ResponseInfo i = ResponseInfo.cancelled();
                        .complete(inull);
                        return;
                    }
                    if (isNotQiniu(info)){
                         = true;
                    }
                    if (isNotQiniu(info) || (info.needRetry() && retried < .)) {
                        nextTask(offsetretried + 1, host);
                        return;
                    }
                    .complete(inforesponse);
                }
            };
            makeFile(hostcomplete.);
            return;
        }
        final int chunkSize = calcPutSize(offset);
        ProgressHandler progress = new ProgressHandler() {
            @Override
            public void onProgress(int bytesWrittenint totalSize) {
                double percent = (double) (offset + bytesWritten) / ;
                if (percent > 0.95) {
                    percent = 0.95;
                }
                ..progress(percent);
            }
        };
        CompletionHandler complete = new CompletionHandler() {
            @Override
            public void complete(ResponseInfo info, JSONObject response) {
                if (!info.isOK()) {
                    if(isCancelled()){
                        ResponseInfo i = ResponseInfo.cancelled();
                        .complete(inull);
                        return;
                    }
                    if (info.statusCode == 701) {
                        nextTask((offset / .) * .retriedhost);
                        return;
                    }
                    if (isNotQiniu(info)){
                         = true;
                    }
                    if (!isNotQiniu(info) && (retried >= . || !info.needRetry())) {
                        .complete(infonull);
                        return;
                    }
                    String host2 = host;
                    if (info.needSwitchServer()) {
                        host2 = .;
                    }
                    nextTask(offsetretried + 1, host2);
                    return;
                }
                String context = null;
                if (response == null) {
                    nextTask(offsetretried + 1, host);
                    return;
                }
                long crc = 0;
                try {
                    context = response.getString("ctx");
                    crc = response.getLong("crc32");
                } catch (JSONException e) {
                    e.printStackTrace();
                }
                if (context == null || crc != ResumeUploader.this.) {
                    nextTask(offsetretried + 1, host);
                    return;
                }
                [offset / .] = context;
                record(offset + chunkSize);
                nextTask(offset + chunkSizeretriedhost);
            }
        };
        if (offset % . == 0) {
            int blockSize = calcBlockSize(offset);
            makeBlock(hostoffsetblockSizechunkSizeprogresscomplete.);
            return;
        }
        String context = [offset / .];
        putChunk(hostoffsetchunkSizecontextprogresscomplete.);
    }
    private int recoveryFromRecord() {
        if (. == null) {
            return 0;
        }
        byte[] data = ..get();
        if (data == null) {
            return 0;
        }
        String jsonStr = new String(data);
        JSONObject obj;
        try {
            obj = new JSONObject(jsonStr);
        } catch (JSONException e) {
            e.printStackTrace();
            return 0;
        }
        int offset = obj.optInt("offset", 0);
        long modify = obj.optLong("modify_time", 0);
        int fSize = obj.optInt("size", 0);
        JSONArray array = obj.optJSONArray("contexts");
        if (offset == 0 || modify !=  || fSize !=  || array == null || array.length() == 0) {
            return 0;
        }
        for (int i = 0; i < array.length(); i++) {
            [i] = array.optString(i);
        }
        return offset;
    }
    private void removeRecord() {
        if (. != null) {
            ..del();
        }
    }
    // save json value
    //{
    //    "size":filesize,
    //    "offset":lastSuccessOffset,
    //    "modify_time": lastFileModifyTime,
    //    "contexts": contexts
    //}
    private void record(int offset) {
        if (. == null || offset == 0) {
            return;
        }
        String data = format(."{\"size\":%d,\"offset\":%d, \"modify_time\":%d, \"contexts\":[%s]}",
                offset, StringUtils.jsonJoin());
        ..set(data.getBytes());
    }
    private boolean isNotQiniu(ResponseInfo info){
        return info.isNotQiniu() && !.hasReturnUrl();
    }
New to GrepCode? Check out our FAQ X