騰訊雲cos物件儲存服務檔案上傳api就是一個大坑

NO IMAGE

一、介紹


物件儲存服務(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;
}
}

注:非常大家瀏覽這篇文章,如果有什麼不懂的或者有錯的地方請大家多多指教,謝謝!