偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

如何在OSS上實(shí)現(xiàn)大文件的斷點(diǎn)下載和上傳

云計(jì)算
OSS對(duì)外提供的是RESTful形式的接口,其最重要的特點(diǎn)之一是無(wú)狀態(tài)性(statelessness),即OSS服務(wù)器不會(huì)保持除了單次請(qǐng)求之外的,任何與其通信的客戶端的通信狀態(tài)。因此對(duì)于斷點(diǎn)續(xù)傳這樣有狀態(tài)功能的實(shí)現(xiàn),關(guān)鍵點(diǎn)在于如何在客戶端完成狀態(tài)維護(hù) 。

OSS(開(kāi)放存儲(chǔ)服務(wù))是面向海量非結(jié)構(gòu)化數(shù)據(jù)對(duì)象的存儲(chǔ)服務(wù)。隨著云計(jì)算的普及和飛速增長(zhǎng),越來(lái)越多的開(kāi)發(fā)者把他們的應(yīng)用建筑在了 OSS之上,然而OSS的開(kāi)發(fā)資料還不是很多。我在這里拋磚引玉,通過(guò)回答一個(gè)經(jīng)常被問(wèn)及的問(wèn)題——如何在OSS上實(shí)現(xiàn)大文件的斷點(diǎn)續(xù)傳功能——希望有更多的高手來(lái)一同分享自己在云存儲(chǔ)上的開(kāi)發(fā)經(jīng)驗(yàn)。

OSS對(duì)外提供的是RESTful形式的接口,其最重要的特點(diǎn)之一是無(wú)狀態(tài)性(statelessness),即OSS服務(wù)器不會(huì)保持除了單次請(qǐng)求之外的,任何與其通信的客戶端的通信狀態(tài)。因此對(duì)于斷點(diǎn)續(xù)傳這樣有狀態(tài)功能的實(shí)現(xiàn),關(guān)鍵點(diǎn)在于如何在客戶端完成狀態(tài)維護(hù) 。在以下章節(jié)中,我以Python為例,介紹如何實(shí)現(xiàn)OSS的斷點(diǎn)下載和斷點(diǎn)上傳。

1. 在OSS上實(shí)現(xiàn)大文件的斷點(diǎn)下載:

所謂斷點(diǎn)下載,就是要從文件已經(jīng)下載的地方開(kāi)始繼續(xù)下載。為了方便理解,我們先來(lái)看一個(gè)從OSS下載一個(gè)文件保存到本地的Python例子。在這個(gè)例子[1]中,我們從一個(gè)名為 “lingyun”的bucket里面,下載一個(gè)叫“example.dat”的文件,并且以相同名字保存在當(dāng)前目錄。

from oss_api import *

HOST="oss.aliyuncs.com"

BUCKET = "lingyun"

OBJECT = "example.dat"

ACCESS_ID = "*******************"

SECRET_ACCESS_KEY = "*******************"

#下載文件

oss = OssAPI(HOST, ACCESS_ID, SECRET_ACCESS_KEY)

res = oss.get_object(BUCKET, OBJECT)

#保存文件

if 200 == res.status:

f = file(OBJECT, 'w')

f.write(res.read())

f.close()

print "Download succeeded."

else:

print "Download failed."

基于上面的代碼,下面的程序顯示了增加斷點(diǎn)續(xù)傳功能的文件下載代碼,變化的地方用粗體標(biāo)注出來(lái)了:

from oss_api import *

HOST="oss.aliyuncs.com" #ads

BUCKET = "lingyun"

OBJECT = "example.dat"

BUFFER_SIZE = 10240 # 寫(xiě)入數(shù)據(jù)的buffer大小

ACCESS_ID = "*******************"

SECRET_ACCESS_KEY = "*******************"

oss = OssAPI(HOST, ACCESS_ID, SECRET_ACCESS_KEY)

# 流式地將數(shù)據(jù)寫(xiě)入文件

def flush_data(file, http_res):

while True:

data = res.read(BUFFER_SIZE)

if len(data) != 0:

file.write(data)

else:

break

# 獲取本地文件長(zhǎng)度

f = file(OBJECT, 'a')

file_len = f.tell()

# 設(shè)置HTTP Header里面的Range參數(shù),跳過(guò)已經(jīng)收到的數(shù)據(jù)

headers = {}

headers["range"] = "bytes=" + str(file_len) + "-"

res = oss.get_object(BUCKET, OBJECT, headers)

if 206 == res.status: # 返回指定范圍內(nèi)的數(shù)據(jù)

flush_data(f, res)

print "Download succeeded."

else: # 下載失敗

print "Download failed."

f.close()

這段代碼和前段代碼相比,有四處發(fā)生了變化:

1) 增加了流式寫(xiě)入本地文件的邏輯。防止下載的數(shù)據(jù)對(duì)象過(guò)大,無(wú)法一下子讀入本地的內(nèi)存中。

2) 向OSS發(fā)送數(shù)據(jù)前,獲取本地文件長(zhǎng)度。

3) 構(gòu)造HTTP的Range Header,要求OSS從指定的位置開(kāi)始下載。

4) 判斷OSS返回的HTTP值,并做出相應(yīng)的處理:如果OSS返回206,說(shuō)明下載的是指定位置范圍內(nèi)的數(shù)據(jù);其他狀態(tài)碼表明“Range”參數(shù)錯(cuò)誤或者發(fā)生異常。

在使用“Range”這個(gè)HTTP 參數(shù)時(shí),請(qǐng)注意以下三點(diǎn):

·Range參數(shù)中的文件位置是從0開(kāi)始,最大值是文件長(zhǎng)度減1

·如果Range參數(shù)填寫(xiě)錯(cuò)誤,OSS將忽視這個(gè)參數(shù)[2]。

·Range參數(shù)設(shè)置正確的話,OSS將返回HTTP狀態(tài)碼206(不是200)以表示返回的是部分?jǐn)?shù)據(jù)

通過(guò)“Range”參數(shù),還可以實(shí)現(xiàn)大文件的并發(fā)下載。這個(gè)功能作為思考題留給各位讀者,感興趣的讀者可以自己實(shí)現(xiàn)一下。OSS官方的SDK里面也提供了一個(gè)多線程下載功能的實(shí)現(xiàn),供大家參考。

2. 在OSS上實(shí)現(xiàn)大文件的斷點(diǎn)上傳:

相對(duì)于斷點(diǎn)下載,斷點(diǎn)上傳的實(shí)現(xiàn)顯然要復(fù)雜得多。OSS提供的解決辦法可以理解為:在客戶端將大文件切分成若干適合公網(wǎng)傳輸?shù)男?shù)據(jù)塊;然后將這些小數(shù)據(jù)塊分別上傳到OSS上;最后在OSS服務(wù)器端將這些小數(shù)據(jù)塊合并成最終的文件。為了實(shí)現(xiàn)這個(gè)功能,OSS單獨(dú)發(fā)布一套上傳API接口——Multipart Upload。這套API接口共有6個(gè):

· Initiate Multipart Upload:初始化一個(gè)Multipart Upload事件

·Upload Part:上傳數(shù)據(jù)塊

· Complete Multipart Upload:完成一個(gè)Multipart Upload事件

· Abort Multipart Upload:中止一個(gè)Multipart Upload事件

·List Multipart Uploads:列出所有存在的Multipart Upload事件

·List Parts:列出某個(gè)Multipart Upload事件下的所有數(shù)據(jù)塊

這套接口中定義了兩個(gè)唯一識(shí)別碼(UUID):Upload ID和Part ID,分別用于標(biāo)識(shí)某個(gè)Multipart Upload上傳事件和某個(gè)數(shù)據(jù)塊。一個(gè)完整的Multipart上傳過(guò)程由以下幾步組成:

1) Initiate Multipart Upload: 初始化一個(gè)Multipart Upload事件

客戶端通知OSS要上傳一個(gè)大文件,OSS返回給客戶端一個(gè)唯一標(biāo)識(shí)這次Multipart上傳事件的Upload ID。Python示例代碼如下:

oss = OssAPI(HOST, ACCESS_ID, SECRET_ACCESS_KEY)

res = oss.init_multi_upload(BUCKET, OBJECT)

下面是OSS返回的HTTP結(jié)果示例:

BUCKET

OBJECT

0004D4184129F5A1A42663160C4C58B1

其中“0004D4184129F5A1A42663160C4C58B1”就是OSS為這次Multipart Upload事件分配的Upload ID。通過(guò)這個(gè)接口,用戶只是在OSS上注冊(cè)了一個(gè)Multipart Upload事件,并沒(méi)有任何文件被創(chuàng)建或改變。你可以對(duì)同一個(gè)文件創(chuàng)建多個(gè)Multipart Upload事件,在這些Multipart Upload事件沒(méi)有完成(Complete)或被中止(Abort)之前,它們都是同時(shí)存在的。

2) Upload Part:上傳數(shù)據(jù)塊

在客戶端將大文件切分成多個(gè)適合公網(wǎng)傳輸大小(建議5MB)的數(shù)據(jù)塊(Part),然后分別上傳到OSS上,并告知OSS這些數(shù)據(jù)塊屬于某個(gè)Upload ID。Python 示例代碼如下:

oss = OssAPI(HOST, ACCESS_ID, SECRET_ACCESS_KEY)

res = oss. upload_part (BUCKET, OBJECT, data, upload_id, part_id )

其中,“data”表示要上傳的Part數(shù)據(jù)內(nèi)容;“upload_id”為此次上傳事件的ID;“part_id”是該數(shù)據(jù)塊的索引。Part ID不但唯一標(biāo)識(shí)這一數(shù)據(jù)塊,還標(biāo)識(shí)了這個(gè)數(shù)據(jù)塊在整個(gè)文件內(nèi)的相對(duì)位置。如果你在同一個(gè)Upload ID下,使用一個(gè)已上傳過(guò)的Part ID上傳了新的數(shù)據(jù),那么OSS上已有的這個(gè)part數(shù)據(jù)將被覆蓋。除了最后一塊Part數(shù)據(jù)沒(méi)有大小限制以外,其他的Part數(shù)據(jù)不能小于5MB。Part ID的有效范圍是1~10000。OSS并不要求屬于同一個(gè)Upload ID的Part ID必須是連續(xù)的,比如:用戶可以只上傳Part ID為1、16、51的數(shù)據(jù)塊;但Part ID的大小表示了數(shù)據(jù)塊之間的相對(duì)位置,例如Part ID為16的數(shù)據(jù)塊,在整個(gè)文件中必須在Part ID為51的數(shù)據(jù)塊之前。Upload Part命令執(zhí)行成功后,OSS會(huì)返回這個(gè)Part數(shù)據(jù)的MD5值給客戶端。用戶需要保存這些MD5值,以便在OSS上最后生成文件時(shí)使用。

3) Complete Multipart Upload:完成一個(gè)Multipart Upload事件

在上傳完所有的數(shù)據(jù)塊到OSS上之后,我們就可以要求OSS在服務(wù)器端將指定的某個(gè)Upload ID所屬的數(shù)據(jù)塊組合成最終的文件。在執(zhí)行該操作時(shí),客戶端需要提供一個(gè)XML格式的文件,其中詳細(xì)列舉出了該文件所需的Part ID及其對(duì)應(yīng)的MD5值。一個(gè)XML的例子如下:

<CompleteMultipartUpload>

<Part>

<PartNumber>1</PartNumber>

<ETag>1DC6D29FD1E1989793B83F5C2FD0C5E0</ETag>

</Part>

<Part>

<PartNumber>16</PartNumber>

<ETag>E17AC4037030A1227D1C1B115619C6F1</ETag>

</Part>

<Part>

<PartNumber>51</PartNumber>

<ETag>807014FC970ED07BA28DE40B20E5BD59</ETag>

</Part>

</CompleteMultipartUpload>

 

 

 

當(dāng)我們構(gòu)建好這個(gè)XML文件后,就可以通過(guò)調(diào)用OSS Python SDK的接口來(lái)發(fā)送完成Multipart Upload事件的請(qǐng)求,代碼示例如下:

oss = OssAPI(HOST, ACCESS_ID, SECRET_ACCESS_KEY)

res = oss.complete_upload(BUCKET, OBJECT, upload_id, part_msg_xml)

OSS收到提交的XML列表后,會(huì)逐一判斷每個(gè)Part是否存在,以及對(duì)應(yīng)的MD5值是否和客戶端提供的MD5值相等。當(dāng)所有的Part驗(yàn)證通過(guò)后,OSS將把這些數(shù)據(jù)Part組合成一個(gè)最終的Object。需要注意的是,用戶可以在這次請(qǐng)求里,不指定所有已經(jīng)上傳的Part。例如,剛才我們成功上傳了1、16和51共三個(gè)數(shù)據(jù)塊到某個(gè)Upload ID名下,我們可以只指定用Part 1、51來(lái)組成最后的文件(注意Part的ID仍然要求是升序的)。當(dāng)OSS生成最終的文件后,會(huì)將沒(méi)有用到的16號(hào)Part刪除,以釋放磁盤(pán)空間。

整個(gè)Multipart Upload流程的Python偽代碼如下所示:

#初始化OSS對(duì)象

oss = OssAPI(HOST, ACCESS_ID, SECRET_ACCESS_KEY)

# 初始化Multipart Upload事件并獲得Upload ID

upload_id = init_multi_upload(oss, bucket_name, object_name)

# 將本地文件分解成為多個(gè)part,并計(jì)算出每個(gè)part的起始位置和長(zhǎng)度

(pos_list, len_list) = split_file_to_part_list(file_name)

# 開(kāi)啟多個(gè)線程來(lái)上傳part

thread_pool = []

for index in range(0, thread_sum):

# 在create_thread_worker 里調(diào)用OSS API上傳指定的part,上傳結(jié)果保存在upload_res

upload_thread = create_thread_worker (oss, file_name, pos_list[index],

len_list[index], upload_res[index])

thread_pool.append(upload_thread)

upload_thread.start()

# 等待所有線程結(jié)束

for upload_thread in thread_pool:

upload_thread.join()

# 創(chuàng)建最終合成文件的part列表(XML格式)

part_msg_xml = create_part_xml(upload_res)

# 要求OSS完成本次Multipart Upload事件

res = complete_multipart_upload(oss, bucket, object, upload_id, part_msg_xml)

上面的例子中,使用到了OSS提供的三個(gè)接口。其余的三個(gè)接口主要提供了對(duì)Upload ID和Part ID的查詢和刪除,方便用戶的管理。由于篇幅原因,這三個(gè)接口就不在這里做展開(kāi)說(shuō)明了,感興趣的朋友可以參考《OSS API文檔》里面的相應(yīng)章節(jié)。

在OSS提供的Multipart Upload方法中,由于各個(gè)數(shù)據(jù)塊之間是相互獨(dú)立的,所以在傳輸過(guò)程中,如果任何一個(gè)數(shù)據(jù)塊傳輸失敗或者進(jìn)程被掛起,只需要客戶端記錄下每個(gè)數(shù)據(jù)塊的上傳狀態(tài),下次重啟上傳進(jìn)程時(shí),繼續(xù)上傳那些還未上傳成功的數(shù)據(jù)塊即可,這樣就實(shí)現(xiàn)了斷點(diǎn)上傳功能。另外,通過(guò)這個(gè)接口,還可以實(shí)現(xiàn)大文件的并發(fā)上傳、向OSS流式地寫(xiě)入數(shù)據(jù)等功能,有興趣的讀者可以自己實(shí)現(xiàn)一下。

后記:

希望通過(guò)這篇文章,大家可以對(duì)如何使用OSS進(jìn)行大文件的斷點(diǎn)下載和上傳的方法有所了解,也希望更多的朋友能分享更多更好的使用OSS的經(jīng)驗(yàn)。

[1]為了便于理解,本文的代碼實(shí)例忽略了一些簡(jiǎn)單的出錯(cuò)處理以及極端情況的判斷邏輯。

[2] 如果其他參數(shù)都合法,這個(gè)請(qǐng)求將符合get object請(qǐng)求的語(yǔ)法,OSS會(huì)返回整個(gè)object的內(nèi)容,而不是用戶期望的部分?jǐn)?shù)據(jù)。

責(zé)任編輯:王程程 來(lái)源: 51CTO
相關(guān)推薦

2015-08-07 15:35:42

ios短點(diǎn)下載源碼

2024-07-02 10:18:18

2021-01-15 11:40:44

文件Java秒傳

2020-04-02 20:07:17

前端vuenote.js

2021-06-01 05:15:36

JavaScript 前端大文件并發(fā)上傳

2022-06-13 14:06:33

大文件上傳前端

2021-04-19 05:41:04

JavaScript大文件下載

2023-09-06 08:33:30

2019-10-11 08:00:00

Linux命令最大文件

2022-06-15 09:01:45

大文件秒傳分片上傳

2017-12-20 15:11:48

iOS緩存文件斷點(diǎn)機(jī)制

2009-12-07 09:45:23

PHP上傳大文件設(shè)置

2014-04-09 10:16:28

Linux文件系統(tǒng)fsck工具

2012-03-27 11:08:23

Java

2024-06-17 09:02:01

2015-12-16 16:01:13

2022-08-05 08:40:37

架構(gòu)

2023-03-09 12:04:38

Spring文件校驗(yàn)

2021-07-10 11:20:44

FreeDOS歸檔文件

2009-11-16 11:41:19

PHP上傳大文件
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)