4

以下のコードで画像をダウンロード・保存して後で開いてみたのですが、後のOpenAsyncでUnauthorizedAccessExceptionがスローされ、ファイルが閉じられていないように見えますが、実際にはIRandomAccessStream/DataWriterが破棄されてしまいました。

HttpClient httpClient = new HttpClient();
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, "http://www.silverlightshow.net/Storage/Users/nikolayraychev/Perspective_Transforms_4.gif");
HttpResponseMessage response = await httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);

//Write Image File
StorageFile imageFile = await ApplicationData.Current.LocalFolder.CreateFileAsync("test.gif", CreationCollisionOption.ReplaceExisting);
using (IRandomAccessStream fs = await imageFile.OpenAsync(FileAccessMode.ReadWrite))
{
    using (DataWriter writer = new DataWriter(fs.GetOutputStreamAt(0)))
    {
        writer.WriteBytes(await response.Content.ReadAsByteArrayAsync());
        await writer.StoreAsync();
        writer.DetachStream();
        await fs.FlushAsync();
    }
 }

 StorageFile imageFile1 = await ApplicationData.Current.LocalFolder.GetFileAsync("test.gif");
 //Exception is throwed here
 using (IRandomAccessStream stream = await imageFile1.OpenAsync(FileAccessMode.Read))
 {
     BitmapImage img = new BitmapImage();
     img.SetSource(stream);
}
4

3 に答える 3

6

同じ問題が発生し、完了する前にストリームオブジェクトとファイルオブジェクトを明示的に破棄する必要がありました。

    var file = await ApplicationData.Current.LocalFolder.CreateFileAsync(filename, Windows.Storage.CreationCollisionOption.ReplaceExisting);
    using (var fs = await file.OpenAsync(Windows.Storage.FileAccessMode.ReadWrite))
    {
        var outStream = fs.GetOutputStreamAt(0);
        var dataWriter = new Windows.Storage.Streams.DataWriter(outStream);
        dataWriter.WriteString("Hello from Test!");
        await dataWriter.StoreAsync();
        dataWriter.DetachStream();
        await outStream.FlushAsync();
        outStream.Dispose(); // 
        fs.Dispose();
    }
于 2012-06-28T11:27:05.717 に答える
0

渡されたストリームをリークしているように見えます

    using (DataWriter writer = new DataWriter(fs.GetOutputStreamAt(0)))

ストリームが参照カウントされている場合 (結局のところ winRT です)、参照はコンストラクターに渡された一時オブジェクトによって保持され、DataWriter のコンストラクターによってインクリメントされます。

一時オブジェクトはガベージ コレクションを待っています。

代わりにこれを行うと機能しますか:

using (var st0 = fs.GetOutputStreamAt(0))
    using (DataWriter writer = new DataWriter(st0))
于 2013-12-28T10:48:16.587 に答える
0

「await」を使用する場合、「使用」することはできません。その理由は、コンパイラが C# の await/async を IL に変換する方法にあります。逆コンパイルして見ることができます。

プロセッサが到着したとき:

await writer.StoreAsync();

実際には、すぐに呼び出し元に戻ります (IL を参照)。"using" を使用しているためDispose、`IRandomAccessStream fs のインターフェイスが呼び出され、リソースが解放されます。これらのリソースは、'StoreAsync' で開始されたスレッドによって必要とされます。

このため、Disposeawait の後に明示的に呼び出す必要があります。

同じ問題が、try/exception/catch ブロックで発生します。

于 2013-01-22T12:15:09.960 に答える