2012-06-23 1 views
4

다음 코드를 사용하여 이미지를 다운로드/저장하고 나중에 열기는했지만 나중에 OpenAsync에서 UnauthorizedAccessException을 throw하면 파일이 닫히지 않았지만 실제로는 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

'대기 중'을 사용할 때는 '사용'할 수 없습니다. 그 이유는 컴파일러가 C# await/async를 IL로 변환하는 이유입니다. 그것을 디 컴파일하여 볼 수 있습니다. 즉시 발신자에게 반환 현실

await writer.StoreAsync(); 

가 (IL 참조)

는 프로세서에 도착하면. 당신이 "using"을 사용하고 있기 때문에, Dispose 인터페이스 인``IRandomAccessStream fs '가 호출되고 리소스가 해제됩니다. 이러한 리소스는 'StoreAsync'에서 시작된 스레드에서 필요합니다.

이러한 이유로, 기다린 후에는 Dispose을 명시 적으로 호출해야합니다.

동일한 문제가 try/exception/catch 블록에 나타납니다. 그것은 스트림이 참조 카운트 경우

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

에 전달 된 스트림을 유출하고 나에게 보이는

+0

비동기 메서드에서 사용할 수 없다고 생각합니다. –

+0

죄송합니다. 제 영어가 확실하지 않은 경우. 물론 비동기 메서드에서 "using"을 사용할 수 있지만 "using"내에서 "await"에 의해 반환 된 결과를 사용할 때는주의해야합니다. await/sync는 언어 설탕에 불과합니다. 기본적으로 컨텍스트를 저장하고 호출자에게 Task 인스턴스를 반환합니다. 그것은 일부 사용자가 기대하는 방식으로 기능을 기다리지 않습니다. IL 코드에서 확인할 수 있습니다. 아래에서 설명하는 것처럼 "이상한"동작이 발생하기 때문에 "사용"을 사용할 때이를 알아야합니다. –

+0

죄송합니다.하지만 그건 잘못되었습니다. http://stackoverflow.com/questions/16566547/do-using-statements-and-await-keywords-play-nicely-in-c-sharp – Stefan

0

는 다음 참조가 전달 임시 객체에 의해 개최됩니다 (이것은 결국 winRT입니다) 생성자가 생성되고 DataWriter의 생성자에 의해 증가됩니다.

임시 개체가 가비지 수집을 기다리고 있습니다. 대신이 작업을 수행 할 경우

그것은 작동합니까 :

using (var st0 = fs.GetOutputStreamAt(0)) 
    using (DataWriter writer = new DataWriter(st0)) 
관련 문제