最近終于有時間寫一點關(guān)于三步上傳的東東了,mulitiple upload又稱三步上傳。三步上傳主要針對那些網(wǎng)絡(luò)環(huán)境不好(傳著傳著就斷了),或者上傳的文件大于5GB,普通的上傳方式滿足不了的上傳。
aws的s3是直接將multiple upload作為一個函數(shù)接口直接提供給開發(fā)者,而BOS和阿里的OSS都需要自己實現(xiàn)那三步:
1. 初始化multiple uploadID
2. 上傳分塊
3. 完成上傳
下面詳細(xì)說明一下這三步,客戶端和BOS服務(wù)器在做什么。
初始化uploadID:
客戶端InitMultiUpload,BOS服務(wù)器端根據(jù)客戶端提供的bucket,object等信息生成在Bucket內(nèi)唯一的Uploadid,并且將Uploadid返回給客戶端;
上傳分片:
客戶端:上傳分片,并提供partNumber。
服務(wù)器端:服務(wù)器端將文件PartData按照Object的邏輯去存儲,并檢查當(dāng)前PartNum為接續(xù)塊或重新上傳的塊,每個Part上傳時的快照信息保存在PartData Object的Meta數(shù)據(jù)中。返回給客戶端已上傳數(shù)據(jù)的MD5信息,以便校驗已上傳數(shù)據(jù)的完整性,斷點上傳支持最新上傳的一塊數(shù)據(jù)的錯誤重新上傳;
注意這里:服務(wù)器端是給客戶端返回每個分片的MD5的。
結(jié)束上傳:
客戶端提交Bucket、Object、Uploadid、PartList給服務(wù)器端。服務(wù)器檢查每一個已上傳的PartData Object的Meta并合并最終的SliceList。如正確,則根據(jù)收集到的SliceList、UserMeta信息生成Meta數(shù)據(jù)寫入Meta表。刪除PartData Object對應(yīng)的所有Meta數(shù)據(jù)。(感覺在這里刪除了每個分片的MD5)
整個multipleUpload就是這樣的一個處理過程,需要注意的是:最后上傳的那個文件是沒有content-MD5的,這就是為什么我們說三步上傳的文件沒有MD5的原因。
理論上,如果每個分片返回的md5值都是對的,那最后合成的文件就是完整并且正確的。以后再說這里怎么去驗證。
下面這個部分主要是結(jié)合實際的python sdk中的代碼,講一下斷點續(xù)傳。(我也不會python哈,寫的比較low,諸位輕批)
這里用到一個pickle庫,這貨的作用就是持久性地保持對象,用這個貨來將我斷點發(fā)生之前的partlist存到文件里。
用法:
import pickle
寫入文件:
f = open("dump.txt", "wb")
partList = [] # then add something into list
pickle.dump(partList, f)
f.close()
從文件讀?。?f = open("dump.txt", "rb")
partList = pickle.load(f)
f.close()
# do something with partList
用兩個代碼來演示一下測試思路:第一個代碼client.py模擬我初始化分片,并上傳分片,在這個過程中,我用鍵盤作為中斷。這段代碼我需要打印出中斷時的partNumber,left_size, offset,并且將partlist保存在一個文件b里。
第二個代碼resume.py根據(jù)uploadID將剩下的分片傳到bos上,并且讀取文件b中的partlist,完成completeUpload。
client.py的大體思路:
初始化upload,生成uploadID:
upload_id = bos_client.initiate_multipart_upload
計算分塊:
offset = 0
part_number = 1
part_list = []
while left_size > 0
進(jìn)行分片
......
上傳part
bos_client.upload_part_from_file
打印left_size
打印offset
#將partlist存儲到文件b中:
f1 = open("./b","wb")
pickle.dump(part_list,f1)
f1.close()
演示:
在本該傳第28個分片的時候,我鍵盤中斷了這次操作,并且打印了left_size和offset。

接下來我們模擬resume.py。
resume.py的大體思路:
upload_id = "bf3167c31f96036f63bec1d1d70ace09"
#如果不知道uploadID,可以用listmultipleUpload根據(jù)bucket name列出來。
f1 = open("./b","rb")
#將文件b里的數(shù)據(jù)讀出來,賦給part_list
part_list = pickle.load(f1)
f1.close
#將上圖中打印出來的數(shù)據(jù)傳給left_size,offset, part_number。
left_size = 501506048
offset = 141557760
part_number = 28
#剩下這一塊的處理跟client.py中while的處理一樣了。
while:
*******
最終,執(zhí)行完畢之后就可以在控制臺看到上傳成功的object了:

這兩段代碼所在github:
https://github.com/tanxiniao/bos/blob/master/client.py
https://github.com/tanxiniao/bos/blob/master/resumable.py
附贈listmultipleUpload的代碼:
https://github.com/tanxiniao/bos/blob/master/listmul.py