
Boto3でS3にオブジェクトをGet・Putする方法まとめ
この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
簡単まとめ
- Binary形式でデータはやり取りする
- BytesIOを使えばオンメモリで使える
Boto3のS3オブジェクトの読み書き
AWS SDKのPython版であるBoto3ではいくつかの方法でオブジェクトのアップロード・ダウンロードが可能です。 大きく分けて次の2つの方式があります。
- ファイルの様な操作(
cpコマンドに近い感じ) - HTTPのような操作
ファイルのような操作は次のように書きます。
bucket.upload_file('/local/path/to/target', 'object/key')
bucket.download_file('object/key', '/local/path/to/target')
ファイル操作のcpコマンドのように引数が[SRC] [DIST]の順になっています。
この方式のAPIを便宜的にファイル版と呼びます。
HTTPのような操作の場合は次のように書きます。
bucket.Object('object/key').get()['Body']
bucket.Object('object/key').put(Body=b'Lorem ipsum dolor sit amet')
HTTPクライアントのようにオブジェクトはBodyを通してやり取りします。
この方式のAPIを便宜的にHTTP版と呼びます。(ファイル版でもHTTP経由で通信します)
以下ではファイル版とHTTP版についてそれぞれ使い方を見ていきます。
準備
以下では次のようなパッケージがインポートされ、変数が定義されているとして話を進めます。
from pathlib import Path
import boto3
import io
s3 = boto3.resource('s3')
bucket = s3.Bucket('boto-io')
KEY = 'ipsum.txt'
ORIGIN_PATH = Path('ipsum.txt')
SAVE_PATH = Path('saved.txt')
ファイル版
ファイル版ではディスクを使用する場合とオンメモリで処理する場合の2パターンを説明します。
直接ディスクから読み込む
ファイルのパスを指定してアップロードする方法です。
bucket.upload_file(str(ORIGIN_PATH), KEY) bucket.download_file(KEY, str(SAVE_PATH))
file objectを使用する
open関数を利用して、ファイルを読み書き可能です。
注意点はバイナリモードでファイルを開くことです。
バイナリのfile objectしか受け付けないようです。
with ORIGIN_PATH.open('rb') as f:
bucket.upload_fileobj(f, KEY)
以下はダメな例です。md5ハッシュが計算できないとのエラーが発生します。
with PATH.open('r') as f:
bucket.upload_fileobj(f, KEY)
Pythonではbオプションをつけてファイルを開くとテキストではなくバイナリとして読み込まれます。
以下はモードによるfile objectの違いです。
BufferedReaderはバイナリのfile objectです。
with ORIGIN_PATH.open('r') as f:
print(f'mode=r: {type(f)}')
# -> "mode=r: <class '_io.TextIOWrapper'>"
with ORIGIN_PATH.open('rb') as f:
print(f'mode=rb: {type(f)}')
# -> "mode=rb: <class '_io.BufferedReader'>"
BytesIOを使用してオンメモリで処理する
バイナリのfile objectであれば良いので、適切な物を使えばオンメモリでファイルのやりとりが可能です。
以下ではBytesIOを使用してファイルのやりとりをしています。
with SAVE_PATH.open('wb') as f:
bucket.download_fileobj(KEY, f)
with io.BytesIO(b'Lorem ipsum dolor sit amet') as f:
bucket.upload_fileobj(f, KEY)
readで読み出す場合は注意が必要です。書き込んだあとはオフセットが進んでいるので0に戻す必要があります。
getvaluesを使用した場合は不要です。
with io.BytesIO() as f:
print(f.read())
# -> b''
f.seek(0)
print(f.read())
# -> b'Lorem ipsum dolor sit amet'
with io.BytesIO() as f:
bucket.download_fileobj(KEY, f)
print(f.getvalue())
# -> b'Lorem ipsum dolor sit amet'
HTTP版
読み込み
obj = bucket.Object(KEY) print(obj.get()['Body'].read())
getはdictを返し、その中にBodyというプロパティが存在します。
このBodyはStreamingBodyです。これはReadOnlyのfile objectのようなものです。
書き込み
書き込む場合はバイナリのfile objectかバイナリそのものが利用可能です。
with ORIGIN_PATH.open('rb') as f:
obj.put(Body=f)
with io.BytesIO(b'Lorem ipsum dolor sit amet') as f:
obj.put(Body=f)
obj.put(Body=b'Lorem ipsum dolor sit amet')
感想
S3にファイルを置いてPythonで読み書きしたい場合の整理ができたと思います。 オンメモリで取り扱う方法も整理できました。






