Python 操作 Azure Blob Storage

sparkdev發表於2017-06-11

筆者在《Azure 基礎:Blob Storage》一文中介紹了 Azure Blob Storage 的基本概念,並通過 C# 程式碼展示瞭如何進行基本的操作。最近筆者需要在 Linux 系統中做類似的事情,於是決定使用 Azure 提供的 Azure Storage SDK for Python 來操作 Blob Storage。這樣今後無論在 Windows 上還是 Linux上,都用 Python 就可以了。對 Azure Blob Storage 概念還不太熟悉的同學請先參考前文

安裝 Azure Storage SDK for Python

最簡單的方式是在安裝了 python 和 pip 的機器上直接執行下面的命令:

pip install azure-storage

安裝完成後通過 pip freeze 命令檢視安裝的版本:

由於 Azure Storage SDK for Python 是一個開源專案,所以你也可以通過原始碼安裝它,請參考官方文件

建立 Blob Container

由於任何一個 Blob 都必須包含在一個 Blob Container 中,所以我們的第一個任務是建立 Blob Container。
SDK 為我們提供了一個名為 BlockBlobService 的物件。通過這個物件我們可以建立並操作 Blob Container。下面的程式碼建立一個名為"nickcon" 的 Container:

程式碼本身很簡單,其中的 account_name 和 account_key 是你的 storage 賬號及其訪問 key。我們使用 GUI 工具 Microsoft Azure Storage Explorer 檢視程式碼操作的結果:

名為 nickcon 的 Blob Container 已經被成功的建立了。

上傳檔案

接下來我們要把本地的檔案上傳到剛才建立的 Blob Container 中。Azure SDK 為我們提供了下面四個方法:

create_blob_from_path #上傳指定路徑的檔案。
create_blob_from_stream #把一個資料流中的內容上傳。
create_blob_from_bytes #上傳一個 bype 陣列。
create_blob_from_text #使用特定的編碼格式上傳字串。

是的,你沒有看錯,所有方法的名字中都沒有 upload 字眼,而是使用了 create。這也說明上傳檔案的本質是在雲端建立一個 Blob 物件。

from azure.storage.blob import BlockBlobService
from azure.storage.blob import ContentSettings

mystoragename = "xxxx"
mystoragekey = "yyyy"
blob_service = BlockBlobService(account_name=mystoragename, account_key=mystoragekey)

blob_service.create_blob_from_path(
    'nickcon',
    'myblobcortana.jpg',
    'cortana-wallpaper.jpg',
    content_settings=ContentSettings(content_type='image/jpg'))

這次我們引入了型別 ContentSettings,主要是指定檔案的型別。注意 create_blob_from_path 方法的第二個引數,我們需要為新的 blob 物件指定一個名字。第一個引數是目標 Container, 第三個引數是要上傳的本地檔案路徑。執行上面的指令碼,會把本地的一張桌布 cortana-wallpaper.jpg 上傳到 Azure Blob Container 中:

在 Container 中建立的 Blob 物件的名稱已經不是原始檔的名稱了,而是我們指定的 myblobcortana.jpg。

控制訪問許可權

存放在 Blob Container 中的檔案都有對應的 URL,這是 Azure Blob Storage 的預設策略。為的是我們可以從任何地方通過 URL 來訪問這些檔案。比如 myblobcortana.jpg 檔案的 URL 為:

https://nickpsdk.blob.core.windows.net/nickcon/myblobcortana.jpg
直接把這個地址貼上到瀏覽器的位址列裡:

啊哦,尷尬了,收到了一個無情的 error!

認真想一下,收到這樣的錯誤是合理的。否則任何人都能看到我儲存的檔案內容,隱私何在?還會有人為 Azure Blob Storage 付費嗎?事情的真相是這樣的,預設情況下我們建立的 Blob Container 和 Blob 物件都是私有的,也就是必須通過賬號和 access key 才能訪問。如果你要想讓內容變成大家都能訪問的公共資源,可以在建立時指定為 PublicAccess。也可以在建立完成後修改它的屬性為 PublicAccess。下面我們把 nickcon Container 設定為 PublicAccess:

from azure.storage.blob import BlockBlobService
from azure.storage.blob import PublicAccess

mystoragename = "xxxx"
mystoragekey = "yyyy"
blob_service = BlockBlobService(account_name=mystoragename, account_key=mystoragekey)

blob_service.set_container_acl('nickcon', public_access=PublicAccess.Container)

此處 import 了 PublicAccess 型別,並呼叫 set_container_acl 方法來修改 Container 的訪問許可權。試試重新重新整理一下網頁:

此時就不要再往你的 Blob Container 中放隱私照了哦!

列出 Blob Container 中的所有檔案

檢查 Container 中都有哪些檔案是很重要的操作,當然我們可以輕鬆的完成:

generator = blob_service.list_blobs('nickcon')
for blob in generator:
print(blob.name)

使用 list_blobs 方法可以獲得 Container 中的所有 Blob 物件。上面的程式碼列印了所有 Blob 物件的名稱。

下載 Blob 物件

和建立 Blob 物件一樣,也有四個方法可以下載 Blob 物件。簡單期間我們只演示 get_blob_to_path 方法,其它的用法類似:

blob_service.get_blob_to_path('nickcon', 'myblobcortana.jpg', 'newimage.png')

其中第二個引數為 Container 中 Blob 物件的名稱,第三個引數為儲存到本地檔案的路徑。

刪除 Blob 物件

有建立自然有刪除,程式碼很簡單,不再囉嗦:

blob_service.delete_blob('nickcon', 'myblobcortana.jpg')

備份 Blob Container 中的檔案

是的,你沒聽錯!
我們相信雲端儲存的安全性,但把重要的資料備份到其它的儲存上也是需要的。下面的程式碼會把一個 Azure Storage Account 中的所有 Blob Container 中的內容備份到本地磁碟上:

from azure.storage.blob import BlockBlobService
import os

mystoragename = "xxxx"
mystoragekey = "yyyy"
blob_service = BlockBlobService(account_name=mystoragename, account_key=mystoragekey)

# 下載一個 Blob Container 中的所有檔案
def downloadFilesInContainer(blobContainName):
    generator = blob_service.list_blobs(blobContainName)
    for blob in generator:
        # 獲得 Blob 檔案的目錄路徑
        blobDirName =  os.path.dirname(blob.name)
        # 把 Blob Container 的名稱也新增為一級目錄
        newBlobDirName = os.path.join(blobContainName, blobDirName)
        # 檢查檔案目錄是否存在,不存在就建立
        if not os.path.exists(newBlobDirName):
            os.makedirs(newBlobDirName)
        localFileName = os.path.join(blobContainName, blob.name)
        blob_service.get_blob_to_path(blobContainName, blob.name, localFileName)

# 獲得使用者所有的 Blob Container
containerGenerator = blob_service.list_containers()
for con in containerGenerator:
    downloadFilesInContainer(con.name)

此處需要注意一點,blob.name 包含了檔案在 container 中的目錄。比如一個檔案在 Blob Container 中的路徑為 abc/test.txt,那麼它的 blog.name 就是 abc/test.txt。要保持檔案在 Blob Container 的名稱及路徑就要在本地建立對應的目錄結構。

總結

最後的 demo 可以簡單的實現備份所有 Blob 檔案的功能。由於微軟把相關介面封裝的很清晰,所以程式碼非常的簡短。使用 Python 的好處是可以在不同的平臺上執行相同的程式碼。當你需要在不同的作業系統中做同樣的事情時,這可太棒了!

相關文章