无法使用REST API从skydrive下载完整的映像文件

我正在为C#中的skydrive 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; } 

这是我试图下载的图像文件

正确的形象

这就是我得到的形象

破碎的图像

这两个图像让我相信我不是在等待完成响应,因为内容长度与我期待的图像大小相同,但我不知道如何让我的代码等待整个响应通过,甚至真的,如果这是我需要采取的方法。

这是我的测试代码,以防它有用

 [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);失败Assert.IsTrue(sameData);

这是因为你没有检查responseStream.Read(contents, 0, (int)response.ContentLength);的返回值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(); 

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