【问题标题】:Get image from URL and upload to Amazon S3从 URL 获取图像并上传到 Amazon S3
【发布时间】:2015-05-30 21:11:50
【问题描述】:

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

这是我的代码:

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)

Amazon API 给我错误“无法确定内容长度”。流文件流以“System.Net.ConnectStream”结尾,我不确定它是否正确。

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

任何想法如何将流转换为 Amazon API 所期望的(长度不变)?

【问题讨论】:

    标签: asp.net .net vb.net file-upload amazon-s3


    【解决方案1】:

    当我使用 GetObjectResponse() 方法及其属性 ResponseStream 将文件从文件夹复制到同一存储桶中的另一个时,我遇到了同样的问题。我注意到 AWS 开发工具包 (2.3.45) 有一些故障,例如在 GetObjectResponse() 中称为 WriteResponseStreamToFile 的另一种方法根本不起作用。这些功能缺失需要一些变通方法。

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

    试试这个(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);
    

    扩展方法

    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();
                }
            }
    

    你也可以创建一个没有字节数组的 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);
    

    扩展方法

        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】:

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

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

      要使您的代码正常工作,请从 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)
      

      【讨论】:

      • 这应该是最好的答案。它不涉及复制内存流。我所要做的就是添加一行来消除错误。 (c#)request.Headers.ContentLength = long.Parse(client.ResponseHeaders.Get("Content-Length"));
      • 这对我从 Zip 存档上传文件有帮助。使用 ZipArchiveEntry,因为我能够使用未压缩的长度。
      猜你喜欢
      • 2012-06-14
      • 2020-10-02
      • 2021-04-27
      • 2011-11-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-27
      相关资源
      最近更新 更多