2012-06-23 47 views
4

我使用下面的代码来下载/保存图像并在以后打开它,但是在以后的OpenAsync中,它会引发UnauthorizedAccessException,看起来该文件不是关闭的,但实际上IRandomAccessStream/DataWriter具有被处置。StorageFile.OpenAsync中的UnauthorizedAccessException

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); 
} 
+0

你不需要刷新任何作家或流。他们在Dispose上冲洗。他们为什么会丢掉你的数据? – usr

+0

等待fs.FlushAsync()只是确保异步刷新操作完成。 – Yanzhi

回答

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(); 
    } 
+0

谢谢史蒂夫,你的代码也适用于我! – Yanzhi

0

当您使用'await'时,您不能“使用”。原因在于编译器如何将C#await/async转换为IL。你可以反编译看到它。

当处理器到达:

await writer.StoreAsync(); 

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

因此,您必须在等待后明确呼叫Dispose

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

+0

我不认为你不能在async方法中使用。 –

+0

对不起,如果我的英语不清楚。当然,你可以在异步方法中使用“using”,但是在“using”中使用“await”返回的结果时需要小心。 等待/同步只是一种语言糖。基本上它保存了一个上下文,并向调用者返回一个Task实例。它不会以某些用户期望的方式等待该功能。你可以在IL代码中看到它。如下所述,在使用“使用”时知道这一点非常重要,因为那样会出现“奇怪”的行为。 –

+0

对不起,但这只是错误的:http://stackoverflow.com/questions/16566547/do-using-statements-and-await-keywords-play-nicely-in-c-sharp – Stefan

0

在我看来,你泄漏传递给

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

流如果流被引用计数的(这是WinRT的毕竟),然后参考将被传递到临时对象举行构造函数,并由DataWriter中的构造函数递增。

临时对象将等待垃圾回收。

请问,如果你不是做它的工作:

using (var st0 = fs.GetOutputStreamAt(0)) 
    using (DataWriter writer = new DataWriter(st0)) 
相关问题