从URL获取图像并上传到Amazon S3

时间:2022-03-04 07:01:10

I'd like to load an image directly from a URL but without saving it on the server, I want to upload it directly from memory to Amazon S3 server.

我想直接从URL加载图像但不保存在服务器上,我想直接从内存上传到Amazon S3服务器。

This is my code:

这是我的代码:

Dim wc As New WebClient
Dim fileStream As IO.Stream = wc.OpenRead("http://www.domain.com/image.jpg")

Dim request As New PutObjectRequest()
request.BucketName = "mybucket"
request.Key = "file.jpg"
request.InputStream = fileStream 
client.PutObject(request)

The Amazon API gives me the error "Could not determine content length". The stream fileStream ends up as "System.Net.ConnectStream" which I'm not sure if it's correct.

Amazon API给出了错误“无法确定内容长度”。流fileStream最终为“System.Net.ConnectStream”,我不确定它是否正确。

The exact same code works with files from the HttpPostedFile but I need to use it in this way now.

完全相同的代码适用于来自HttpPostedFile的文件,但我现在需要以这种方式使用它。

Any ideas how I can convert the stream to become what Amazon API is expecting (with the length intact)?

任何想法如何我可以转换流成为亚马逊API期望(长度完整)?

2 个解决方案

#1


3  

I had the same problem when I'm using the GetObjectResponse() method and its propertie ResponseStream to copy a file from a folder to another in same bucket. I noted that the AWS SDK (2.3.45) have some faults like a another method called WriteResponseStreamToFile in GetObjectResponse() that simply doesn't work. These lacks of functions needs some workarounds.

当我使用GetObjectResponse()方法及其属性ResponseStream将文件从文件夹复制到同一存储桶中的另一个文件夹时,我遇到了同样的问题。我注意到AWS SDK(2.3.45)有一些错误,比如GetObjectResponse()中另一个名为WriteResponseStreamToFile的方法,它根本不起作用。缺乏这些功能需要一些解决方法。

I solved the problem openning the file in array of bytes and putting it in a MemoryStream object.

我解决了以字节数组打开文件并将其放入MemoryStream对象的问题。

Try this (C# code)

试试这个(C#代码)

WebClient wc = new WebClient();
Stream fileStream =  wc.OpenRead("http://www.domain.com/image.jpg");

byte[] fileBytes = fileStream.ToArrayBytes();

PutObjectRequest request  = new PutObjectRequest();
request.BucketName = "mybucket";
request.Key = "file.jpg";
request.InputStream = new MemoryStream(fileBytes);
client.PutObject(request);

The extesion method

extesion方法

public static byte[] ToArrayBytes(this Stream input)
        {
            byte[] buffer = new byte[16 * 1024];
            using (MemoryStream ms = new MemoryStream())
            {
                int read;
                while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
                {
                    ms.Write(buffer, 0, read);
                }
                return ms.ToArray();
            }
        }

You can also create a MemoryStream without an array of bytes. But after the first PutObject in S3, the MemoryStream will be discarted. If you need to put others objects, I recommend the first option

您还可以创建没有字节数组的MemoryStream。但是在S3中的第一个PutObject之后,MemoryStream将被丢弃。如果您需要放置其他对象,我建议您使用第一个选项

 WebClient wc = new WebClient();
 Stream fileStream =  wc.OpenRead("http://www.domain.com/image.jpg");

 MemoryStream fileMemoryStream = fileStream.ToMemoryStream();  

 PutObjectRequest request  = new PutObjectRequest();
 request.BucketName = "mybucket";
 request.Key = "file.jpg";
 request.InputStream = fileMemoryStream ;
 client.PutObject(request);

The extesion method

extesion方法

    public static MemoryStream ToMemoryStream(this Stream input)
    {
        byte[] buffer = new byte[16 * 1024];

        int read;
        MemoryStream ms = new MemoryStream();
        while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
        {
            ms.Write(buffer, 0, read);
        }
        return ms;
    }

#2


1  

I had the same problem in a similar scenario.

在类似的场景中我遇到了同样的问题。

The reason for the error is that to upload an object the SDK needs to know the whole content length that is going to be uploaded. To be able to obtain stream length it must be seekable, but the stream returned from WebClient is not. To indicate the expected length set Headers.ContentLength in PutObjectRequest. The SDK will use this value if it cannot determine length from the stream object.

出错的原因是上传SDK需要知道将要上传的整个内容长度的对象。为了能够获得流长度,它必须是可搜索的,但是从WebClient返回的流不是。要指示预期长度,请在PutObjectRequest中设置Headers.ContentLength。如果SDK无法从流对象确定长度,则SDK将使用此值。

To make your code work, obtain content length from the response headers returned by the call made by WebClient. Then set PutObjectRequest.Headers.ContentLength. Of course this relies on the server returned content length value.

要使代码正常工作,请从WebClient调用返回的响应头中获取内容长度。然后设置PutObjectRequest.Headers.ContentLength。当然这取决于服务器返回的内容长度值。

Dim wc As New WebClient
Dim fileStream As IO.Stream = wc.OpenRead("http://www.example.com/image.jpg")
Dim contentLength As Long = Long.Parse(client.ResponseHeaders("Content-Length"))

Dim request As New PutObjectRequest()
request.BucketName = "mybucket"
request.Key = "file.jpg"
request.InputStream = fileStream 
request.Headers.ContentLength = contentLength
client.PutObject(request)

#1


3  

I had the same problem when I'm using the GetObjectResponse() method and its propertie ResponseStream to copy a file from a folder to another in same bucket. I noted that the AWS SDK (2.3.45) have some faults like a another method called WriteResponseStreamToFile in GetObjectResponse() that simply doesn't work. These lacks of functions needs some workarounds.

当我使用GetObjectResponse()方法及其属性ResponseStream将文件从文件夹复制到同一存储桶中的另一个文件夹时,我遇到了同样的问题。我注意到AWS SDK(2.3.45)有一些错误,比如GetObjectResponse()中另一个名为WriteResponseStreamToFile的方法,它根本不起作用。缺乏这些功能需要一些解决方法。

I solved the problem openning the file in array of bytes and putting it in a MemoryStream object.

我解决了以字节数组打开文件并将其放入MemoryStream对象的问题。

Try this (C# code)

试试这个(C#代码)

WebClient wc = new WebClient();
Stream fileStream =  wc.OpenRead("http://www.domain.com/image.jpg");

byte[] fileBytes = fileStream.ToArrayBytes();

PutObjectRequest request  = new PutObjectRequest();
request.BucketName = "mybucket";
request.Key = "file.jpg";
request.InputStream = new MemoryStream(fileBytes);
client.PutObject(request);

The extesion method

extesion方法

public static byte[] ToArrayBytes(this Stream input)
        {
            byte[] buffer = new byte[16 * 1024];
            using (MemoryStream ms = new MemoryStream())
            {
                int read;
                while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
                {
                    ms.Write(buffer, 0, read);
                }
                return ms.ToArray();
            }
        }

You can also create a MemoryStream without an array of bytes. But after the first PutObject in S3, the MemoryStream will be discarted. If you need to put others objects, I recommend the first option

您还可以创建没有字节数组的MemoryStream。但是在S3中的第一个PutObject之后,MemoryStream将被丢弃。如果您需要放置其他对象,我建议您使用第一个选项

 WebClient wc = new WebClient();
 Stream fileStream =  wc.OpenRead("http://www.domain.com/image.jpg");

 MemoryStream fileMemoryStream = fileStream.ToMemoryStream();  

 PutObjectRequest request  = new PutObjectRequest();
 request.BucketName = "mybucket";
 request.Key = "file.jpg";
 request.InputStream = fileMemoryStream ;
 client.PutObject(request);

The extesion method

extesion方法

    public static MemoryStream ToMemoryStream(this Stream input)
    {
        byte[] buffer = new byte[16 * 1024];

        int read;
        MemoryStream ms = new MemoryStream();
        while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
        {
            ms.Write(buffer, 0, read);
        }
        return ms;
    }

#2


1  

I had the same problem in a similar scenario.

在类似的场景中我遇到了同样的问题。

The reason for the error is that to upload an object the SDK needs to know the whole content length that is going to be uploaded. To be able to obtain stream length it must be seekable, but the stream returned from WebClient is not. To indicate the expected length set Headers.ContentLength in PutObjectRequest. The SDK will use this value if it cannot determine length from the stream object.

出错的原因是上传SDK需要知道将要上传的整个内容长度的对象。为了能够获得流长度,它必须是可搜索的,但是从WebClient返回的流不是。要指示预期长度,请在PutObjectRequest中设置Headers.ContentLength。如果SDK无法从流对象确定长度,则SDK将使用此值。

To make your code work, obtain content length from the response headers returned by the call made by WebClient. Then set PutObjectRequest.Headers.ContentLength. Of course this relies on the server returned content length value.

要使代码正常工作,请从WebClient调用返回的响应头中获取内容长度。然后设置PutObjectRequest.Headers.ContentLength。当然这取决于服务器返回的内容长度值。

Dim wc As New WebClient
Dim fileStream As IO.Stream = wc.OpenRead("http://www.example.com/image.jpg")
Dim contentLength As Long = Long.Parse(client.ResponseHeaders("Content-Length"))

Dim request As New PutObjectRequest()
request.BucketName = "mybucket"
request.Key = "file.jpg"
request.InputStream = fileStream 
request.Headers.ContentLength = contentLength
client.PutObject(request)