2012-06-23 3 views
4

Я использовал следующий код, чтобы загрузить/сохранить изображение и открыть его позже, но в дальнейшем OpenAsync он выбрасывает UnauthorizedAccessException, кажется, что файл не близко, но на самом деле IRandomAccessStream/DataWriter имеет были удалены.UnauthorizedAccessException в StorageFile.OpenAsync

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# ждут/асинхронно в IL. Вы можете декомпилировать его.

Когда процессор приходит к:

await writer.StoreAsync(); 

в действительности она возвращается к вызывающему абоненту (см IL). Поскольку вы используете «использование», вызывается интерфейс Dispose «IRandomAccessStream fs» и ресурсы освобождаются. Эти ресурсы требуются потоком, инициированным в «StoreAsync».

По этой причине вы должны позвонить по телефону Dispose явно, после ожидания.

Та же проблема возникает в блоках try/exception/catch.

+0

Я не думаю, что это правда, что вы не можете использовать использование в асинхронном методе. –

+0

Извините, если мой английский не был ясен. Конечно, вы можете использовать «использование» в асинхронном методе, но вам нужно быть осторожным, когда вы используете результат, возвращаемый «ожидание» в «использовании». Ожидание/синхронизация - это всего лишь язык сахара. В основном это сохраняет контекст и возвращает экземпляр задачи вызывающему. Он НЕ дожидается, когда функция будет выглядеть так, как ожидают некоторые пользователи. Вы можете увидеть это в коде 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)) 
Смежные вопросы