腾讯云cos对象存储服务文件上传api就是一个大坑

一、介绍

对象存储服务(Cloud Object Service)是基于腾讯多年海量服务经验,对外提供的可靠、安全、易用的海量存储服务。提供多样化接入方式,以及全国部署的上传加速集群,可以无缝衔接CDN进行加速下载。

二、cos 文件上传api源码

/**     * 单个文件上传,适用于小文件     *   * @param bucketName     *            bucket名称   * @param remotePath     *            远程文件路径     * @param localPath  *            本地文件路径     * @return 服务器端返回的操作结果,成员code为0表示成功,具体参照文档手册     * @throws Exception     */ public String uploadFile(String bucketName, String remotePath,          String localPath) throws Exception {        if (!FileProcess.isLegalFile(localPath)) {          String errorMsg = localPath                 + " is not file or not exist or can't be read!";            LOG.error(errorMsg);            JSONObject errorRet = new JSONObject();         errorRet.put(ResponseBodyKey.CODE, ErrorCode.PARAMS_ERROR);         errorRet.put(ResponseBodyKey.MESSAGE, errorMsg);            return errorRet.toString();     }       FileInputStream localFileInputStream = null;        try {           localFileInputStream = FileProcess.getFileInputStream(localPath);           return uploadFile(bucketName, remotePath, localFileInputStream);        } catch (Exception e) {         LOG.error("UploadFile {} occur a error {}", localPath, e.toString());           throw e;        } finally {         FileProcess.closeFileStream(localFileInputStream, localPath);       }   }

三、为什么是个坑

从上面的代码中,我们可以看出,使用cos的文件上传接口,我们需要指定远程文件地址(就是我们需存储到cos的那个目录下的那个文件比如/folder/1.txt)和本地文件路径。下面我用三点来说为什么是个坑

1.在实际的开发中,很多时候,我们上传文件到web后端,在controller中以file对象存在,像spring mvc 的MultipartFile 对象是不容易获取到服务器缓存该文件的路径;

2.在手机app上传文件,app通常会采用http的方式把文件以字节数组的方式传到后台服务的,莫非还需要们在后台服务缓存一下;

3.在分布式系统中一般会把文件操作放在一个专门提供上传下载的分布式服务中比如采用dubbo,在这种方式下,一般采用字节或者采用BASE64Decoder转化成字符串来传送文件内容,如果采用cos自己原有的接口,还需要缓存一下文件。

     综上所述,cos原有的接口就是一个坑,根本不实用。那么有什么好的解决方法呢,请继续往下面看。

四,解决方法

在api中自己定义了一个扩展方法,把最后的localpath改为接收字节数组,代码如下:

/**     * 流文件上传,适用于小文件,自定义扩展方法  *   * @param bucketName     *            bucket名称   * @param remotePath     *            远程文件路径     * @param fileContent    *            文件字节数组     * @return 服务器端返回的操作结果,成员code为0表示成功,具体参照文档手册     * @throws Exception     */ public String uploadFileExt(String bucketName, String remotePath,           byte[] fileContent) throws Exception {      String url = getEncodedCosUrl(bucketName, remotePath);      String shaDigest = CommonCodecUtils.getFileSha1(fileContent);       HashMap<String, String> postData = new HashMap<String, String>();       postData.put(RequestBodyKey.OP, RequestBodyValue.OP_UPLOAD);        postData.put(RequestBodyKey.SHA, shaDigest);        long expired = getExpiredTimeInSec();       String sign = Sign.appSignature(appId, secretId, secretKey, expired,                bucketName);        HashMap<String, String> httpHeader = new HashMap<String, String>();     httpHeader.put(RequestHeaderKey.Authorization, sign);       return httpSender.sendFileRequest(url, httpHeader, postData,                fileContent, timeOut);  }

有需要的朋友只需把该方法,拷贝到CosCloud类当中就可以了。

五.把文件转化成字节数组方式

1、springmvc 上传controller中MultipartFile payfile文件参数获取成字节数组方式:

payfile.getBytes();//这个方法就可以获取字节数组

2、将file文件转化成字节数组方式

public static byte[] getByte(File file) throws Exception {        byte[] bytes = null;        if (file != null) {         InputStream is = new FileInputStream(file);         int length = (int) file.length();           if (length > Integer.MAX_VALUE) // 当文件的长度超过了int的最大值         {               System.out.println("this file is max ");                return null;            }           bytes = new byte[length];           int offset = 0;         int numRead = 0;            while (offset < bytes.length                    && (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) {                offset += numRead;          }           // 如果得到的字节长度和file实际的长度不一致就可能出错了         if (offset < bytes.length) {                System.out.println("file length is error");             return null;            }           is.close();     }       return bytes;   }}

注:非常大家浏览这篇文章,如果有什么不懂的或者有错的地方请大家多多指教,谢谢!