最近在使用Python访问S3,进行文件的上传和下载。因为都是私有数据,所以不能直接通过Web进行下载。AWS提供了一个Python库boto3,来完成相关的操作。但是其文档写得相当差,没有详细的tutorial和examples。自己做了一些google搜索,结合boto3文档,对一些常用操作进行说明。
boto3使用当前最新版本1.4.6。
AWS配置
访问S3需要aws_access_key_id和aws_secret_access_key。在boto3提供的API中,可以指定这两个值。但是把安全相关的这些信息放到代码中并不是一个好的选择。所以,我们通过awscli配置,将其存放到~/.aws/credentials。boto3的API在访问S3时,会自动从该文件中读取相关信息。
awscli可以通过pip install awscli进行安装。
下载文件
下载文件需要提供bucket名和文件名。
可以直接下载并保存到本地文件中:
bucket_name = 'mybucket'
file_name = 'hello.txt'
local_file_name = '/tmp/hello.txt'
s3 = boto3.resource('s3')
s3.Object(bucket_name, file_name).download_file(local_file_name)
也可以下载file object,保存到buffer中,以避免不必要的文件读写。
buf = io.BytesIO()
s3 = boto3.resource('s3')
s3.Object(bucket_name, file_name).download_fileobj(buf)
如果想把S3作为一个read stream,可以使用Object的get() method:
s3 = boto3.resource('s3')
obj = s3.Object(bucket_name, file_name)
chunk_size = 64*1024
stream = obj.get().get('Body')
while True:
data = stream.read(chunk_size)
if not len(data):
raise StopIteration
yield data
上传文件
上传文件可以同样可以有三种方式。
使用upload_file:
s3 = boto3.resource('s3')
s3.Object(bucket_name, file_name).upload_file(local_file)
使用upload_fileobj:
s3 = boto3.resource('s3')
with open(local_file, 'rb') as f:
s3.Object(bucket_name, file_name).upload_fileobj(f)
使用put() method:
s3 = boto3.resource('s3')
with open(local_file, 'rb') as f:
s3.Object(bucket_name, file_name).put(Body=f)
检测文件是否存在
有的时候我们需要检测文件是否在S3中已经存在,以避免不必要的误操作。可以使用如下代码。根据这篇文章Fastest way to find out if a file exists in S3,如果对大量文件进行操作的话,性能应该不错。
s3 = boto3.resource('s3')
bucket = s3.Bucket(bucket_name)
for obj in bucket.objects.filter(Prefix=file_name):
if obj.key == file_name:
return True
return False