Android客户端实现七牛云存储文件上传
1.简单文件上传 上传模型如下。
1.1获得Token
不管是简单文件上传,还是分片上传、断点续传 都需要首先访问服务器,以获得上传凭证信息Token.。用于测试时,可以用本地模拟Token信息(有安全隐患,容易造成数据和空间数据危险)本地模拟Token信息 1.2《本地模拟Token》
1.1.1本地模拟Token.
/** * 获取token 本地生成 * * @return */ private String getToken() { Mac mac = new Mac(QiNiuConfig.QINIU_AK, QiNiuConfig.QINIU_SK); PutPolicy putPolicy = new PutPolicy(QiNiuConfig.QINIU_BUCKNAME); putPolicy.returnBody = "{\"name\": $(fname),\"size\": \"$(fsize)\",\"w\": \"$(imageInfo.width)\",\"h\": \"$(imageInfo.height)\",\"key\":$(etag)}"; try { String uptoken = putPolicy.token(mac); System.out.println("debug:uptoken = " + uptoken); return uptoken; } catch (AuthException e) { e.printStackTrace(); } catch (JSONException e) { e.printStackTrace(); } return null; }
1.2简单文件实现上传(参考七牛官方文档)
小于4M,采用简单文件上传模式。从回调中获得上传最后信息,是失败或者是成功。
data = <File对象、或 文件路径、或 字节数组> String key = <指定七牛服务上的文件名,或 null>; String token = <从服务端SDK获取>; UploadManager uploadManager = new UploadManager(); uploadManager.put(data, key, token, new UpCompletionHandler() { @Override public void complete(String key, ResponseInfo info, JSONObject response) { Log.i("qiniu", info); } }, null);
回调参数说明:
参数 | 说明 |
key | 即uploadManager.put(file, key, …)方法指定的key。key 指定存储在云服务器上的文件名字。并会通过返回值返回出来。 |
info | http请求的状态信息等,可记入日志。isOK()返回 true表示上传成功。 |
response | 七牛反馈的信息。可从中解析保存在七牛服务的key等信息,具体字段取决于上传策略的设置。 |
1.2.1 记录上传进度 (参考七牛官方文档)
用与进度显示。更新UI进度操作。
uploadManager.put(data, key, token,handler, new UploadOptions(null, null, false, new UpProgressHandler(){ public void progress(String key, double percent){ Log.i("qiniu", key + ": " + percent); } }, null));
注:progress(key, percent)中的key 即uploadManager.put(file, key, …)方法指定的key
1.2.2取消上传
设置标志位,可以取消上传操作。直接覆盖uploadManager,最后一个上传参数。
private volatile boolean isCancelled; ... // 某方法中执行取消:isCancelled = true; ... uploadManager.put(data, key, token,handler, new UploadOptions(null, null, false, progressHandler, new UpCancellationSignal(){ public boolean isCancelled(){ return isCancelled; } }));
1.2.3记录断点
分片上传中,可将各个已上传的块记录下来,再次上传时,已上传的部分不用再次上传。 断点记录类需实现 com.qiniu.android.storage.Recorder 接口。已提供保存到文件的 FileRecorder 实现。
String dirPath = <断点记录文件保存的文件夹位置> FileRecorder fr = new FileRecorder(dirPath) UploadManager uploadManager = new UploadManager(fr); uploadManager.put(data, key, ...) //默认使用 key 的url_safe_base64编码字符串作为断点记录文件的文件名。避免记录文件冲突(特别是key指定为null时),也可自定义文件名: UploadManager uploadManager = new UploadManager(fr, new KeyGenerator(){ public String gen(String key, File file){ // 不必使用url_safe_base64转换,uploadManager内部会处理 // 该返回值可替换为基于key、文件内容、上下文的其它信息生成的文件名 return key + file.getName(); } });
2.分片文件上传(官方文档解释)
2.1官方相关概念
2.2分片上传相关代码例子 (Demo这里)
得到要上传的文件信息转化为Upload对象。
private void preUpload(Uri uri) { // 此参数会传递到回调 String passObject = "test: " + uri.getEncodedPath() + "passObject"; String qiniuKey = UUID.randomUUID().toString(); PutExtra extra = null; Upload up = UpApi.build(getAuthorizer(), qiniuKey, uri, this, extra, passObject, uploadHandler); addUp(up); }
执行上传操作,UpApi.execuete(up)会根据文件大小,执行分块上传文件操作。
private synchronized void doUpload() { System.out.println("doup: 启动上传任务"); for (Upload up : ups) { if (UpApi.isSliceUpload(up)) { String sourceId = generateSourceId(up.getUpParam(), up.getPassParam()); List<Block> bls = null; try { bls = load(sourceId); } catch (IOException e) { e.printStackTrace(); } // 设置以前上传的断点记录。 直传会忽略此参数 up.setLastUploadBlocks(bls); } // UpApi.execute(up, bls); Executor executor = UpApi.execute(up); executors.add(executor); } System.out.println("doup: 启动上传任务完毕"); start = System.currentTimeMillis(); }
3断点续传
参考Demo:这里:
相关代码:
public void doResumableUpload(final Uri uri, PutExtra extra) { uploadUri = uri; final MyBlockRecord record = MyBlockRecord.genFromUri(this, uri); tvUploadInfo.setText("连接中"); String key = null; if (extra != null) { extra.params = new HashMap<String, String>(); extra.params.put("x:a", "bb"); } List<Block> blks = record.loadBlocks(); String s = "blks.size(): " + blks.size() + " ==> "; for (Block blk : blks) { s += blk.getIdx() + ", "; } final String pre = s + "\r\n"; uploading = true; executor = ResumableIO.putFile(this, auth, key, uri, extra, blks, new CallBack() { @Override public void onSuccess(UploadCallRet ret) { uploading = false; String key = ret.getKey(); String redirect = "http://" + MyActivity.bucketName + ".qiniudn.com/" + key; String redirect2 = "http://" + MyActivity.bucketName + ".u.qiniudn.com/" + key; tvUploadInfo.setText(pre + "上传成功! ret: " + ret.toString() + " \r\n可到" + redirect + " 或 " + redirect2 + " 访问"); record.removeBlocks(); clean(); } @Override public void onProcess(long current, long total) { int percent = (int) (current * 100 / total); tvUploadInfo.setText(pre + "上传中: " + current + "/" + total + " " + current / 1024 + "K/" + total / 1024 + "K; " + percent + "%"); // int i = 3/0; progressBar.setProgress((int) percent); } @Override public void onBlockSuccess(Block blk) { record.saveBlock(blk); } @Override public void onFailure(CallRet ret) { uploading = false; clean(); tvUploadInfo.setText(pre + "错误: " + ret.toString()); } }); }