2012-05-01 1 views
1

Я работаю над быстрой оболочкой для API skydrive на C#, но сталкивается с проблемами при загрузке файла. Для первой части файла все проходит отлично, но тогда начинают возникать различия в файле, и вскоре после этого все становится нулевым. Я уверен, что это просто я не правильно читаю поток.Не удается загрузить полный файл изображения из skydrive с помощью REST API

Это код, я использую для загрузки файла:

public const string ApiVersion = "v5.0"; 
public const string BaseUrl = "https://apis.live.net/" + ApiVersion + "/"; 

public SkyDriveFile DownloadFile(SkyDriveFile file) 
{ 
    string uri = BaseUrl + file.ID + "/content"; 
    byte[] contents = GetResponse(uri); 
    file.Contents = contents; 
    return file; 
} 

public byte[] GetResponse(string url) 
{ 
    checkToken(); 
    Uri requestUri = new Uri(url + "?access_token=" + HttpUtility.UrlEncode(token.AccessToken)); 
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestUri); 
    request.Method = WebRequestMethods.Http.Get; 
    WebResponse response = request.GetResponse(); 
    Stream responseStream = response.GetResponseStream(); 
    byte[] contents = new byte[response.ContentLength]; 
    responseStream.Read(contents, 0, (int)response.ContentLength); 
    return contents; 
} 

Это файл образ, который я пытаюсь загрузить

The Correct Image

И это изображение, которое я я получаю

Broken Image

Эти два изображения заставляют меня поверить, что я не жду ответа, чтобы закончить работу, потому что длина контента такая же, как размер изображения, который я ожидаю, но я не уверен, как сделать мой код ждет, когда весь ответ пройдет или даже действительно, если это тот подход, который мне нужно принять.

Вот мой тестовый код в случае, если это полезно

[TestMethod] 
public void CanUploadAndDownloadFile() 
{ 
    var api = GetApi(); 
    SkyDriveFolder folder = api.CreateFolder(null, "TestFolder", "Test Folder"); 
    SkyDriveFile file = api.UploadFile(folder, TestImageFile, "TestImage.png"); 
    file = api.DownloadFile(file); 
    api.DeleteFolder(folder); 
    byte[] contents = new byte[new FileInfo(TestImageFile).Length]; 
    using (FileStream fstream = new FileStream(TestImageFile, FileMode.Open)) 
    { 
     fstream.Read(contents, 0, contents.Length); 
    } 
    using (FileStream fstream = new FileStream(TestImageFile + "2", FileMode.CreateNew)) 
    { 
     fstream.Write(file.Contents, 0, file.Contents.Length); 
    } 
    Assert.AreEqual(contents.Length, file.Contents.Length); 
    bool sameData = true; 
    for (int i = 0; i < contents.Length && sameData; i++) 
    { 
     sameData = contents[i] == file.Contents[i]; 
    } 
    Assert.IsTrue(sameData); 
} 

Это терпит неудачу на Assert.IsTrue(sameData);

+0

Вы пытались использовать веб-клиент вместо этого? http://msdn.microsoft.com/en-us/library/ez801hhe.aspx –

ответ

2

Это происходит потому, что вы не проверять возвращаемое значение responseStream.Read(contents, 0, (int)response.ContentLength);. Read не гарантирует, что он будет читать response.ContentLength байт. Вместо этого он возвращает количество прочитанных байтов. Вы можете использовать петлю или stream.CopyTo.

Что-то вроде этого:

WebResponse response = request.GetResponse(); 
MemoryStream m = new MemoryStream(); 
response.GetResponseStream().CopyTo(m); 
byte[] contents = m.ToArray(); 
1

Как LB уже сказал, вы должны продолжать называть Read() до тех пор, пока не прочтете весь поток.

Хотя Stream.CopyTo скопирует весь поток, он не гарантирует, что прочитает количество ожидаемых байтов. Следующий метод позволит решить эту проблему и вызвать исключение IOException, если он не читает указанную длину ...

public static void Copy(Stream input, Stream output, long length) 
    { 
     byte[] bytes = new byte[65536]; 
     long bytesRead = 0; 
     int len = 0; 
     while (0 != (len = input.Read(bytes, 0, Math.Min(bytes.Length, (int)Math.Min(int.MaxValue, length - bytesRead))))) 
     { 
      output.Write(bytes, 0, len); 
      bytesRead = bytesRead + len; 
     } 
     output.Flush(); 
     if (bytesRead != length) 
      throw new IOException(); 
    }