2015-03-26 4 views
1

Я хотел бы загрузить изображение непосредственно с URL-адреса, но без сохранения его на сервере, я хочу загрузить его непосредственно из памяти на сервер Amazon S3.Получить изображение с 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) 

Амазонка API дает мне ошибку «Не удалось определить длину содержимого». Поток fileStream заканчивается как «System.Net.ConnectStream», который я не уверен, правильно ли это.

Точный же код работает с файлами из HttpPostedFile, но я должен использовать его таким образом.

Любые идеи о том, как я могу преобразовать поток, чтобы стать тем, что ожидает API Amazon (с длиной нетронутой)?

ответ

2

У меня была такая же проблема, когда я использую метод GetObjectResponse() и его СВОЙСТВ ResponseStream скопировать файл из папки в другую в то же ведро. Я отметил, что в AWS SDK (2.3.45) есть некоторые ошибки, как другой метод, называемый WriteResponseStreamToFile в GetObjectResponse(), который просто не работает. Эти недостатки функций требуют обходных решений.

Я решил проблему, открыв файл в массиве байтов и поместив его в объект 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); 

Метод 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(); 
      } 
     } 

Вы также можете создать MemoryStream без массива байтов. Но после первого PutObject в S3 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); 

Метод 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; 
    } 
1

Я была такая же проблема в подобном сценарии.

Причина ошибки заключается в том, что для загрузки объекта SDK необходимо знать всю длину контента, которая будет загружена. Чтобы иметь возможность получать длину потока, он должен быть доступен для поиска, но поток, возвращаемый из WebClient, не является. Чтобы указать ожидаемую длину, установите Headers.ContentLength в PutObjectRequest. 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) 
+0

Это должен быть лучший ответ. Это не связано с копированием потока памяти. Все, что мне нужно было сделать, это добавить одну строку, чтобы удалить ошибку. (C#) 'request.Headers.ContentLength = long.Parse (client.ResponseHeaders.Get (" Content-Length "));' – herostwist