我正在为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);
答案 0 :(得分: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 :(得分: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();
}