1

C#でskydrive APIのクイックラッパーに取り組んでいますが、ファイルのダウンロードで問題が発生しています。ファイルの最初の部分では、すべてが正常に実行されますが、ファイルに違いが生じ始め、その後すぐにすべてがnullになります。ストリームを正しく読んでいないのは私だけだとかなり確信しています。

これは私がファイルをダウンロードするために使用しているコードです:

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

これは私がダウンロードしようとしている画像ファイルです

正しい画像

そしてこれは私が得ている画像です

壊れた画像

これらの2つの画像は、コンテンツの長さが期待する画像のサイズと同じであるため、応答が完了するのを待っていないことを私に信じさせますが、どのように作成するかはわかりませんコードは、応答全体が完了するのを待つか、それが私がとる必要のあるアプローチである場合でも実際に待ちます。

これが役立つ場合に備えて私のテストコードです

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

4

2 に答える 2

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();
于 2012-05-01T19:09:12.163 に答える
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();
    }
于 2012-05-01T19:50:51.010 に答える