【问题标题】:How to upload a file to S3 without creating a temporary local file如何在不创建临时本地文件的情况下将文件上传到 S3
【发布时间】:2012-09-16 05:36:19
【问题描述】:

是否有任何可行的方法可以将动态生成的文件直接上传到亚马逊s3,而无需先创建本地文件然后上传到s3服务器?我用蟒蛇。谢谢

【问题讨论】:

  • 下面的答案解释了两种方法。但是,如果您遇到只能获取文件的 API,您可能需要查看 tempfile.TemporaryFile;使用正确的参数,您将获得一个类似文件的对象,尽可能接近不是真实文件。 (在 POSIX 上,这意味着它没有目录条目,除非必要,否则不会备份到磁盘;在 Windows 上,它实际上是一个文件对象的包装对象,该对象确实存在于临时目录中,直到您关闭它,这并不总是好的够了,所以你可能不得不 PyWin32 CreateFile 并做一些更复杂的代码来得到你想要的)。
  • 目前 boto 没有此功能。 Key.open_write() 方法尚未实现。一旦它是你将有答案。 set_contents_from_stream() 据称可以从流对象中读取,但它实际上需要一个文件...我不知道它是否可以以某种方式使用...

标签: python amazon-s3 amazon


【解决方案1】:

这是一个下载图像(使用请求库)并将其上传到 s3 的示例,而不写入本地文件:

import boto
from boto.s3.key import Key
import requests

#setup the bucket
c = boto.connect_s3(your_s3_key, your_s3_key_secret)
b = c.get_bucket(bucket, validate=False)

#download the file
url = "http://en.wikipedia.org/static/images/project-logos/enwiki.png"
r = requests.get(url)
if r.status_code == 200:
    #upload the file
    k = Key(b)
    k.key = "image1.png"
    k.content_type = r.headers['content-type']
    k.set_contents_from_string(r.content)

【讨论】:

    【解决方案2】:

    您可以使用 Python 标准库中的 BytesIO

    from io import BytesIO
    bytesIO = BytesIO()
    bytesIO.write('whee')
    bytesIO.seek(0)
    s3_file.set_contents_from_file(bytesIO)
    

    【讨论】:

    • 或者,以bytesIO为数据:s3.upload_fileobj(data,'','')
    • @Roy Hyunjin Han - 你能不能美化一下,我在翻译这个建议以完成目标时遇到了麻烦。我在这里有一个帖子:stackoverflow.com/questions/59165498/…
    • 我一直在使用 s3.put_object(Body=bytesIO.getvalue(), Bucket='bucket', Key='key') 对我来说效果很好。
    【解决方案3】:

    boto 库的 Key 对象有几个您可能感兴趣的方法:

    有关使用 set_contents_from_string 的示例,请参阅 boto 文档的 Storing Data 部分,为完整起见粘贴在此处:

    >>> from boto.s3.key import Key
    >>> k = Key(bucket)
    >>> k.key = 'foobar'
    >>> k.set_contents_from_string('This is a test of S3')
    

    【讨论】:

    • 但是如何在 set_contents_from_file 中实现,并且它接受本地存储​​在磁盘上的文件
    • @shihon 我不明白你的问题。
    • 看到我使用像 file = request.file['name'] 这样的请求得到了一个文件,然后我将它保存在本地 os.save(os.path.加入(路径,文件)),从那里我设置s3键和set_contents_from_filename(os.path.join(路径,文件)),我需要直接在s3上保存文件而不是比先在本地保存,然后在 s3 上...
    • 我得到“AttributeError:'_io.BytesIO'对象没有属性'encode'”
    【解决方案4】:

    我假设您使用的是botobotoBucket.set_contents_from_file() 将接受StringIO 对象,并且您为将数据写入文件而编写的任何代码都应该很容易适应写入StringIO 对象。或者如果你生成一个字符串,你可以使用set_contents_from_string()

    【讨论】:

    • 我在 python file = request.file['name'] set_contents_from_file(file.readlines()) 中尝试过,但它需要一个字符串,所以我迭代并获取字符串,但它给了我 AttributeError : 'str' 对象没有属性 'tell'
    • 那是因为你传递的是一个字符串,而不是我建议的 StringIO 对象......
    • 哦,是的,你是对的,但无论是 StringIO(file) 还是 StringIO(file.readlines()),文件上传到 s3 但无法打开在浏览器上只显示空白符号... .
    • 好吧,如果你有一个file,你可以把它传进去,不需要先读...
    【解决方案5】:
    def upload_to_s3(url, **kwargs):
        '''
        :param url: url of image which have to upload or resize to upload
        :return: url of image stored on aws s3 bucket
        '''
    
        r = requests.get(url)
        if r.status_code == 200:
            # credentials stored in settings AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY
            conn = boto.connect_s3(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, host=AWS_HOST)
    
            # Connect to bucket and create key
            b = conn.get_bucket(AWS_Bucket_Name)
            k = b.new_key("{folder_name}/{filename}".format(**kwargs))
    
            k.set_contents_from_string(r.content, replace=True,
                                       headers={'Content-Type': 'application/%s' % (FILE_FORMAT)},
                                       policy='authenticated-read',
                                       reduced_redundancy=True)
    
            # TODO Change AWS_EXPIRY
            return k.generate_url(expires_in=AWS_EXPIRY, force_http=True)
    

    【讨论】:

      【解决方案6】:

      我有一个 dict 对象,我想将它作为 json 文件存储在 S3 上,而不创建本地文件。下面的代码对我有用:

      from smart_open import smart_open
      
      with smart_open('s3://access-key:secret-key@bucket-name/file.json', 'wb') as fout:
          fout.write(json.dumps(dict_object).encode('utf8'))
      

      【讨论】:

        【解决方案7】:

        在boto3中,有一种上传文件内容的简单方法,无需使用以下代码创建本地文件。我已经修改了 boto3 的 JimJty 示例代码

        import boto3
        from botocore.retries import bucket
        import requests
        from io import BytesIO
        # set the values
        aws_access_key_id=""
        aws_secret_access_key=""
        region_name=""
        bucket=""
        key=""
        
        session = boto3.session.Session(aws_access_key_id=aws_access_key_id,aws_secret_access_key=aws_secret_access_key, region_name=region_name)
        s3_client = session.client('s3')
        #download the file
        url = "http://en.wikipedia.org/static/images/project-logos/enwiki.png"
        r = requests.get(url)
        if r.status_code == 200:    
            #convert content to bytes, since upload_fileobj requires file like obj
            bytesIO = BytesIO(bytes(r.content))    
            with bytesIO as data:
                s3_client.upload_fileobj(data, bucket, key)
        

        【讨论】:

          【解决方案8】:

          您可以尝试使用smart_open (https://pypi.org/project/smart_open/)。我正是为此使用它:直接在 S3 中写入文件。

          【讨论】:

            【解决方案9】:

            鉴于静态加密现在是一种非常需要的数据标准,smart_open 不支持这个 afaik

            【讨论】:

              【解决方案10】:

              此实现是将图像列表(NumPy 列表、OpenCV 图像对象)直接上传到 S3 的示例

              注意:您需要在上传文件时将图像对象转换为字节或缓冲区转换为字节,这样您才能上传文件而不会出现损坏错误

              #Consider you have images in the form of a list i.e. img_array
              import boto3
              
              s3 = boto3.client('s3')
              res_url = []
              
              for i,img in enumerate(img_array):
                      s3_key = "fileName_on_s3.png"
                      response = s3.put_object(Body=img.tobytes(), Bucket='bucket_name',Key=s3_key,ACL='public-read',ContentType= 'image/png')
                      s3_url = 'https://bucket_name.s3.ap-south-1.amazonaws.com/'+s3_key
                      res_url.append(s3_url)
              #res_url is the list of URLs returned from S3 Upload
              

              【讨论】:

                【解决方案11】:

                boto3 更新:

                aws_session = boto3.Session('my_access_key_id', 'my_secret_access_key')
                s3 = aws_session.resource('s3')
                s3.Bucket('my_bucket').put_object(Key='file_name.txt', Body=my_file)
                

                【讨论】:

                  【解决方案12】:

                  我遇到了类似的问题,想知道是否有最终答案,因为使用下面的代码,“starwars.json”会继续在本地保存,但我只想将每个循环的 .json 文件推送到 S3 和没有文件存储在本地。

                  for key, value in star_wars_actors.items():
                  
                  response = requests.get('http:starwarsapi/' + value)
                  
                  
                  
                  data = response.json()
                  
                  
                  with open("starwars.json", "w+") as d:
                      json.dump(data, d, ensure_ascii=False, indent=4)
                  
                  
                  
                  s3.upload_file('starwars.json', 'test-bucket',
                                 '%s/%s' % ('test', str(key) + '.json'))
                  

                  【讨论】:

                  • @susanne 嗨,我也遇到了类似的问题,想知道你最终做出了什么决定?
                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2013-03-01
                  • 2017-05-02
                  • 1970-01-01
                  • 1970-01-01
                  • 2022-01-14
                  • 2015-03-11
                  相关资源
                  最近更新 更多