【问题标题】:UnauthorizedAccessException in StorageFile.OpenAsyncStorageFile.OpenAsync 中的 UnauthorizedAccessException
【发布时间】:2012-06-23 08:52:06
【问题描述】:

我使用以下代码下载/保存图像并稍后打开它,但是在以后的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);
}

【问题讨论】:

  • 您不需要刷新任何写入器或流。它们在 Dispose 上冲洗。为什么他们会丢弃你的数据?
  • await fs.FlushAsync() 只是确保异步刷新操作完成。

标签: c# io windows-runtime file-access


【解决方案1】:

我遇到了同样的问题,必须在完成之前显式处理流和文件对象。

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

【讨论】:

    【解决方案2】:

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

    当处理器到达时:

    await writer.StoreAsync();
    

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

    因此,您必须在等待之后显式调用Dispose

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

    【讨论】:

    • 我不认为你不能在异步方法中使用 using。
    • 对不起,如果我的英语不清楚。当然你可以在异步方法中使用“using”,但是在“using”中使用“await”返回的结果时需要小心。 await/sync 只是一种语言糖。基本上,它保存一个上下文并将一个 Task 实例返回给调用者。它不会以某些用户期望的方式等待函数。你可以在 IL 代码中看到它。使用“使用”时了解这一点很重要,因为随后会发生“奇怪”行为,如下所述。
    • 抱歉,这完全是错误的:stackoverflow.com/questions/16566547/…
    【解决方案3】:

    在我看来,您正在泄漏传递给的流

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

    如果流是引用计数的(毕竟是winRT),那么一个引用将由传递给构造函数的临时对象持有,并由DataWriter中的构造函数递增。

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

    如果你这样做,它是否有效:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-07
      • 1970-01-01
      • 2013-09-04
      • 2010-09-16
      • 2011-07-03
      • 1970-01-01
      相关资源
      最近更新 更多