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

当您使用“等待”时,您不能“使用”。原因是编译器如何将您的 C# await/async 转换为 IL。你可以反编译看看。

当处理器到达时:

await writer.StoreAsync();

实际上它会立即返回给调用者(参见 IL)。由于你使用的是“using”,所以Dispose调用了`IRandomAccessStream fs的接口并释放了资源。在“StoreAsync”中启动的线程需要这些资源。

因此,您必须Dispose在 await 之后显式调用。

同样的问题出现在 try/exception/catch 块中。

于 2013-01-22T12:15:09.960 回答
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 回答