有没有一种方法可以将数据直接从python请求流传输到minio存储桶

时间:2019-09-17 17:29:26

标签: python python-3.x stream python-requests minio

我正在尝试向服务器发出GET请求以检索tiff图像。然后,我想使用MinIO python SDK中的put_object方法将其直接流式传输到MinIO。

我知道可以通过将图像保存到临时文件中然后上传来实现这一点,但是我想看看是否可以跳过该步骤。

我尝试直接插入字节响应并使用BytesIO对其进行包装,但我认为我缺少了一些东西。

r = requests.get(url_to_download, stream=True)
Minio_client.put_object("bucket_name", "stream_test.tiff", r.content, r.headers['Content-length'])

我得到以下错误

  

AttributeError:“字节”对象没有属性“读取”

非常感谢您的帮助!

2 个答案:

答案 0 :(得分:2)

您可以像这样直接将文件流式传输到minio存储桶中:

import requests

from pathlib import Path
from urllib.parse import urlparse

from django.conf import settings
from django.core.files.storage import default_storage

client = default_storage.client
object_name = Path(urlparse(response.url).path).name
bucket_name = settings.MINIO_STORAGE_MEDIA_BUCKET_NAME

with requests.get(url_to_download, stream=True) as r:
    content_length = int(r.headers["Content-Length"])
    result = client.put_object(bucket_name, object_name, r.raw, content_length)

或者您可以直接使用Django文件字段:

with requests.get(url_to_download, stream=True) as r:
    # patch the stream to make django-minio-storage belief
    # it's about to read from a legit file
    r.raw.seek = lambda x: 0
    r.raw.size = int(r.headers["Content-Length"])
    model = MyModel()
    model.file.save(object_name, r.raw, save=True)

Dinko Pehar的RawIOBase提示确实很有帮助,非常感谢。但是您必须使用response.raw而不是response.content,它会立即下载文件,并且在尝试存储大型视频时确实非常不便。

答案 1 :(得分:0)

在MinIO上阅读关于put_object的{​​{3}},有一些示例如何将新对象添加到对象存储服务器。这些示例仅说明了如何添加文件。

这是put_object函数的定义:

put_object(bucket_name, object_name, data, length, content_type='application/octet-stream', metadata=None, progress=None, part_size=510241024)

我们对data参数感兴趣。它指出:

  

任何实现io.RawIOBase的python对象。

documentation是原始二进制I / O的基类。它还定义了方法read

如果我们要使用RawIOBase内置函数来尝试返回r.content的有效属性列表,则可以检查read是否存在:

'read' in dir(r.content)->返回False

这就是为什么您获得AttributeError: 'bytes' object has no attribute 'read'的原因。这是因为type(r.content)bytes类。


您可以将r.content转换为继承自RawIOBase的类。也就是说,使用io.BytesIO类。要获取对象的大小(以字节为单位),我们可以使用io.BytesIO(r.content).getbuffer().nbytes

因此,如果要将流的原始字节数据传输到存储桶,请将bytes类转换为io.BytesIO类:

import io
import requests

r = requests.get(url_to_download, stream=True)
raw_img = io.BytesIO(r.content)
raw_img_size = raw_img.getbuffer().nbytes

Minio_client.put_object("bucket_name", "stream_test.tiff", raw_img, raw_img_size)

注意:示例显示了从文件读取二进制数据并通过从st_size读取stat_result属性(通过使用os.stat()函数返回)来获取其大小。 / p>

st_size等同于io.BytesIO(r.content).getbuffer().nbytes