2012-05-01 2 views
1

Je travaille sur un wrapper rapide pour l'API skydrive en C#, mais je rencontre des problèmes avec le téléchargement d'un fichier. Pour la première partie du fichier, tout se passe bien, mais alors il commence à y avoir des différences dans le fichier et peu de temps après, tout devient nul. Je suis à peu près sûr que c'est juste moi qui ne lis pas le flux correctement.Impossible de télécharger le fichier image complet à partir de skydrive en utilisant l'API REST

C'est le code que je utilise pour télécharger le fichier:

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

Ceci est le fichier image que je suis en train de télécharger

The Correct Image

Et ceci est l'image que je je suis obtenir

Broken Image

Ces deux images m'amènent à croire que je n'attends pas la réponse pour finir, parce que la longueur du contenu est la même que la taille de l'image que j'attends, mais je ne suis pas sûr de savoir comment faire mon code attend que la réponse soit complète ou même si c'est l'approche que je dois adopter.

Voici mon code de test dans le cas où il est utile

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

Il échoue à Assert.IsTrue(sameData);

+0

Avez-vous essayé d'utiliser un client Web à la place? http://msdn.microsoft.com/en-us/library/ez801hhe.aspx –

Répondre

2

Ceci est parce que vous ne cochez pas la valeur de retour de responseStream.Read(contents, 0, (int)response.ContentLength);. Read ne garantit pas qu'il lira response.ContentLength octets. Au lieu de cela, il renvoie le nombre d'octets lus. Vous pouvez utiliser une boucle ou stream.CopyTo là.

Quelque chose comme ceci:

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

Comme LB déjà dit, vous devez continuer à appeler Read() jusqu'à ce que vous avez lu la totalité du flux.

Bien que Stream.CopyTo copiera le flux entier, il ne garantit pas la lecture du nombre d'octets attendus. La méthode suivante va résoudre ceci et déclencher une IOException si elle ne lit pas la longueur spécifiée ...

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