え?使わない?きっと使う時がくるさ!
何でも入るBlob StorageはAWSもGCPにもあるんだよ?使わなきゃ損!
安いので大容量データの格納だったり、一時的な格納スペースとして活用されているのかな?
個人的なハマりポイントもまとめながら手順を説明してきます。
目次
最終目標
- Azure Blob Storageからファイルをダウンロード/アップロードする
前回までのあらすじ
この記事でできること
Pythonについては次の投稿でまとめます。
- Azure Blob Storageの作成
環境条件
今回は以下の条件で進めます。
- Python 3.9.1
- Azureのアカウントがあること(無料枠有もしくはクレカ登録済)
Python - コードを書く
どんな処理を書くか?
- storageというContainerを作成
- storageというContainer内のinputフォルダ内の全てのファイルをダウンロード
- ダウンロードしたファイルをstorageというContainer内のoutputフォルダ内に全てアップロード
ざっくりこんな感じのことを実現しようと思います。
どういう感じて書くか?
- 必要なモジュールをインストール
- データをダウンロードするクラスを作成
- データをアップロードするクラスを作成
- main.pyに必要な処理を記載する
必要なモジュールをインストール
$ pip install azure-blob-storage
Azure Blob Storageからデータをダウンロードするクラス
データをダウンロードする処理をまとめたクラスを作成します。
ソース上はBlobにアクセスする部分とローカル部分にファイルを作成する部分に分けています。
Blobアクセス箇所
def download_blob(self):
my_blobs = self.my_container.list_blobs()
self._logger.info(f'Download target blob : {os.path.join(self.target_folder, "*")}')
for blob in my_blobs:
if blob.name.startswith(self.target_folder) :
dirname, filename = os.path.split(blob.name)
bytes = self.my_container.get_blob_client(blob).download_blob().readall()
self.save_blob(blob.name, bytes)
else:
self._logger.debug(f'Ignore blob : {blob.name}')
ローカルファイル作成箇所
def save_blob(self, file_name, file_content):
os.makedirs(os.path.dirname(file_name), exist_ok=True)
with open(file_name, "wb") as file:
file.write(file_content)
Azure Blob Storageからデータをアップロードするクラス
データをアップロードする処理をまとめたクラスを作成します。
微妙にダウンロードと処理の書き方が違います。
def upload_local_file(self):
try:
files = glob.glob(os.path.join(self.source_folder, '*'))
# local file read
for file in files:
# self._logger.info(f'Delete blob file :{os.path.join(self.target_folder, os.path.basename(file))}')
# blob_client.delete_blob()
blob_client = self.blob_service_client.get_blob_client(container=self.container_name, blob=os.path.join(self.target_folder, os.path.basename(file)))
self._logger.info(f'Upload local file :{os.path.join(self.target_folder, os.path.basename(file))}')
with open(file, "rb") as data:
blob_client.upload_blob(data)
except ResourceExistsError as ex:
self._logger.error(f"[ResourceExistsError][{self.__module__}]:{ex.message}")
except ResourceNotFoundError as ex:
self._logger.error(f"[ResourceNotFoundError][{self.__module__}]:{ex.message}")
except Exception as ex:
self._logger.error(f"[ExceptionError][{self.__module__}]:{ex.message}")
アップロード先にファイルが存在する場合はResourceExistsエラーが発生します。
回避方法としては事前にBlobをダウンロードして、リネームして置いておくぐらいでしょうか。
ちなみにbdelete_blob()メソッドを走らせても同様のエラーが発生します。
main.pyに処理を書きます
上記2つのクラスをmain.pyに書いていきます。
main.pyの上部に前回作成したAzure Blob Storageの接続文字列やコンテナ名称などを記載します。
connection_string:str = r'<your connection string>'
container_name:str = r'<your container name>'
download_path:str = r'<your download folder path>'
upload_path:str = r'<your upload folder path>'
接続文字列定義後はクラスを呼び出して、各メソッドをそれぞれ呼び出しているだけです。
azure_blob_file_downloader = AzureBlobFileDownloader(connection_string, container_name, download_path)
azure_blob_file_downloader.download_blob()
azure_blob_file_uploader = AzureBlobFileUploader(connection_string, container_name, upload_path, download_path)
azure_blob_file_uploader.upload_local_file()
全てのソースは下記にあります。(色々Loggerとか使用していますが不要であれば削除してください。)
処理結果
VSCodeのターミナル上から実行するとこんな形になります。
アップロード先に既に同じファイルが存在する場合は下記のようなエラーが発生します。
その際はAzure Blob Storage上からファイルを削除してください。
inputフォルダにあるinput.txtが、
outputフォルダにコピーされます。
以上