boto3 download_file中的IO错误

时间:2016-09-19 09:29:03

标签: python-2.7 amazon-s3 aws-lambda boto3

背景

我正在使用boto3代码从s3下载文件。这是以下代码。

for record in event['Records']:
    bucket = record['s3']['bucket']['name']
    key = record['s3']['object']['key']
    print (key)
    if key.find('/') < 0 :
    if len(key) > 4 and key[-5:].lower() == '.json': //File is uploaded outside any folder

        download_path = '/tmp/{}{}'.format(uuid.uuid4(), key)
    else:
        download_path = '/tmp/{}/{}'.format(uuid.uuid4(), key)//File is uploaded inside a folder

如果在s3存储桶中上传了新文件,则会触发此代码并通过此代码下载新上传的文件。

当在任何文件夹之外上传时,此代码可以正常工作。

但是,当我在目录中上传文件时,会发生IO错误。 这是我遇到的IO错误的转储。

  

[Errno 2]没有这样的文件或目录:   的 /tmp/316bbe85-fa21-463b-b965-9c12b0327f5d/test1/customer1.json.586ea9b8 :   IO错误

test1是我的s3存储桶中的目录,其中上传了customer1.json。

查询

有任何想法,如何解决此错误?

4 个答案:

答案 0 :(得分:2)

引发错误是因为您试图将文件下载并保存到不存在的目录中。在下载文件之前使用os.mkdir来创建目录。

# ...
else:
    item_uuid = str(uuid.uuid4())
    os.mkdir('/tmp/{}'.format(item_uuid))
    download_path = '/tmp/{}/{}'.format(item_uuid, key)  # File is uploaded inside a folder

注意:在使用系统路径时使用os.path.join()会更好。因此,上面的代码可以重写为:

# ...
else:
    item_uuid = str(uuid.uuid4())
    os.mkdir(os.path.join(['tmp', item_uuid]))
    download_path = os.path.join(['tmp', item_uuid, key]))

也可能因为你包括&#39; / tmp /&#39;而引起错误。在s3存储桶文件的下载路径中,不要包含tmp文件夹,因为它可能不存在于s3上。通过使用这些文章确保您正确的方式:

答案 1 :(得分:1)

我遇到了同样的问题,错误消息引起了很多混乱(文件名后的随机字符串扩展名)。在我的情况下,这是由缺少的目录路径引起的,该目录路径不存在。

答案 2 :(得分:0)

感谢帮助Andriy Ivaneyko,我找到了使用boto3的解决方案。

使用以下代码,我可以完成任务。

this.form.markAsPristine()

答案 3 :(得分:0)

您的代码存在问题,因为download_path错误。每当您尝试下载s3存储桶中目录下的任何文件时,下载路径都将变为:

download_path = /tmp/<uuid><object key name>
where <object key name>  = "<directory name>/<object name>"

这使得下载路径为:

download_path = /tmp/<uuid><directory name>/<object key name>

代码将失败,因为不存在带有uuid目录名称的目录。您的代码仅允许下载/ tmp目录下的文件。

要解决此问题,请考虑在创建下载路径时拆分密钥,还可以避免检查文件在存储桶中的上传位置。这只会在下载路径中使用目标文件名。例如:

for record in event['Records']:
    bucket = record['s3']['bucket']['name']
    key = record['s3']['object']['key']
    print (key) 
    download_path = '/tmp/{}{}'.format(uuid.uuid4(), key.split('/')[-1])