如何将S3存储桶中的映像文件直接读入内存?

Dim*_*ims 11 python matplotlib amazon-s3 boto3

我有以下代码

import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import numpy as np
import boto3
s3 = boto3.resource('s3', region_name='us-east-2')
bucket = s3.Bucket('sentinel-s2-l1c')
object = bucket.Object('tiles/10/S/DG/2015/12/7/0/B01.jp2')
object.download_file('B01.jp2')
img=mpimg.imread('B01.jp2')
imgplot = plt.imshow(img)
plt.show(imgplot)
Run Code Online (Sandbox Code Playgroud)

它的工作原理.但它首先将文件下载到当前目录的问题.是否可以直接在RAM中读取文件并将其解码为图像?

小智 31

我建议使用io模块将文件直接读入内存,而不必使用临时文件.

例如:

import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import numpy as np
import boto3
import io

s3 = boto3.resource('s3', region_name='us-east-2')
bucket = s3.Bucket('sentinel-s2-l1c')
object = bucket.Object('tiles/10/S/DG/2015/12/7/0/B01.jp2')

file_stream = io.StringIO()
object.download_fileobj(file_stream)
img = mpimg.imread(file_stream)
# whatever you need to do
Run Code Online (Sandbox Code Playgroud)

io.BytesIO如果您的数据是二进制的,您也可以使用.

  • 如果“预期字符串参数,得到字节”是您的错误,请记住尝试 `io.BytesIO()` 而不是 `io.StringIO()`。对于 boto3 和 python 3,这是关键 (8认同)
  • 我收到相同的错误:TypeError:预期的字符串参数,得到了“字节” (4认同)
  • 当我执行代码的最后一行时,我收到“读取文件末尾”错误 (4认同)
  • @NeeleshkumarSrinivasanMannur 我也遇到同样的错误。你找到解决办法了吗? (3认同)
  • object.download_fileobj(file_stream)给我一个错误,TypeError:预期为unicode参数,得到了'str' (2认同)

bea*_*ker 25

从 Greg Merritt 的回答中进一步发展以解决评论部分中的所有错误,使用BytesIO代替StringIO,使用 PILImage代替matplotlib.image

以下函数适用于python3boto3。同样,write_image_to_s3功能也是一种奖励。

from PIL import Image
from io import BytesIO
import numpy as np

def read_image_from_s3(bucket, key, region_name='ap-southeast-1'):
    """Load image file from s3.

    Parameters
    ----------
    bucket: string
        Bucket name
    key : string
        Path in s3

    Returns
    -------
    np array
        Image array
    """
    s3 = boto3.resource('s3', region_name='ap-southeast-1')
    bucket = s3.Bucket(bucket)
    object = bucket.Object(key)
    response = object.get()
    file_stream = response['Body']
    im = Image.open(file_stream)
    return np.array(im)

def write_image_to_s3(img_array, bucket, key, region_name='ap-southeast-1'):
    """Write an image array into S3 bucket

    Parameters
    ----------
    bucket: string
        Bucket name
    key : string
        Path in s3

    Returns
    -------
    None
    """
    s3 = boto3.resource('s3', region_name)
    bucket = s3.Bucket(bucket)
    object = bucket.Object(key)
    file_stream = BytesIO()
    im = Image.fromarray(img_array)
    im.save(file_stream, format='jpeg')
    object.put(Body=file_stream.getvalue())
Run Code Online (Sandbox Code Playgroud)


Hye*_*ung 14

格雷格梅里特的答案如下是更好的方法.

我想建议在模块中使用Python的NamedTemporaryFiletempfile.它会创建临时文件,在文件关闭时将被删除(感谢@NoamG)

import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import numpy as np
import boto3
import tempfile

s3 = boto3.resource('s3', region_name='us-east-2')
bucket = s3.Bucket('sentinel-s2-l1c')
object = bucket.Object('tiles/10/S/DG/2015/12/7/0/B01.jp2')
tmp = tempfile.NamedTemporaryFile()

with open(tmp.name, 'wb') as f:
    object.download_fileobj(f)
    img=mpimg.imread(tmp.name)
    # ...Do jobs using img
Run Code Online (Sandbox Code Playgroud)

  • 即使对于担心下载大于 512 MB 的文件的 AWS Lambda 用户来说,即使临时文件也很重要,因为 lambda 在 /tmp 中将用户限制为 512 MB (3认同)
  • 这应该可以正常工作,但在幕后,创建了一个真正的文件,并在关闭后立即销毁。 (2认同)

GSt*_*tav 9

使用客户端的方法略有不同:

import boto3
import io
from matplotlib import pyplot as plt

client = boto3.client("s3")

bucket='my_bucket'
key= 'my_key'

outfile = io.BytesIO()
client.download_fileobj(bucket, key, outfile)
outfile.seek(0)
img = plt.imread(outfile)

plt.imshow(img)
plt.show()
Run Code Online (Sandbox Code Playgroud)


Adr*_*ing 8

通过指定文件格式,可以流式传输图像imread().

import boto3
from io import BytesIO
import matplotlib.image as mpimg
import matplotlib.pyplot as plt

resource = boto3.resource('s3', region_name='us-east-2')
bucket = resource.Bucket('sentinel-s2-l1c')

image_object = bucket.Object('tiles/10/S/DG/2015/12/7/0/B01.jp2')
image = mpimg.imread(BytesIO(image_object.get()['Body'].read()), 'jp2')

plt.figure(0)
plt.imshow(image)
Run Code Online (Sandbox Code Playgroud)


小智 5

object = bucket.Object('tiles/10/S/DG/2015/12/7/0/B01.jp2')
img_data = object.get().get('Body').read()
Run Code Online (Sandbox Code Playgroud)

  • 感谢您提供此代码片段,它可能会提供一些即时帮助。一个正确的解释[将大大提高](https://meta.stackexchange.com/q/114762) 通过展示为什么这是一个很好的解决问题的方法,它的教育价值,并且会使它对未来类似的读者更有用,但不相同,问题。请编辑您的答案以添加解释,并说明适用的限制和假设。 (13认同)