保存文件时出现未经授权访问异常

6

我有以下代码在一个Windows 8 C#应用程序中,从服务器获取并存储图像:

        private async Task httpFetcher()
    {
        HttpClient httpClient = new HttpClient();
        HttpRequestMessage request = new HttpRequestMessage(
HttpMethod.Get, "http://www.example.com/fakeImageRotator.php"); // FOR EXAMPLE
        HttpResponseMessage response = await httpClient.SendAsync(request,
            HttpCompletionOption.ResponseHeadersRead);

        Uri imageUri;
        BitmapImage image = null;

        try
        {
            var imageFile = await ApplicationData.Current.LocalFolder.CreateFileAsync(
         "test.png", CreationCollisionOption.ReplaceExisting);
            var fs = await imageFile.OpenAsync(FileAccessMode.ReadWrite);
            DataWriter writer = new DataWriter(fs.GetOutputStreamAt(0));
            writer.WriteBytes(await response.Content.ReadAsByteArrayAsync());
            await writer.StoreAsync();
            writer.DetachStream();
            await fs.FlushAsync();
            writer.Dispose();

            if (Uri.TryCreate(imageFile.Path, UriKind.RelativeOrAbsolute, out imageUri))
            {
                image = new BitmapImage(imageUri);
            }

        }
        catch (Exception e)
        {
            return;
        }

        image1.Source = image;
    }

看起来我在这一行随机出现了错误:


                var imageFile = await ApplicationData.Current.LocalFolder.CreateFileAsync(
         "test.png", CreationCollisionOption.ReplaceExisting);

这种情况并不总是发生,所以我不确定如何确定问题所在。以下是所有错误细节:

捕获到UnauthorizedAccessException

访问被拒绝。(HRESULT 异常:0x80070005 (E_ACCESSDENIED)) 位于 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 位于 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 位于 System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() 位于 TestApp.MainPage.d__4.MoveNext() in d:\TestApp\TestApp\MainPage.xaml.cs:line 86

3个回答

6
更新-“拒绝访问”错误是由多个因素引起的。
第一个原因与图像下载有关。似乎下载代码中的某些内容正在保持文件打开状态。以下是简化的下载代码。
第二个原因与BitmapImage对象保持文件打开状态有关。有关更多信息,请参见此帖子:在WinRT中使用DataTemplate中先前使用的图像文件时删除文件时出现“拒绝访问” 解决第二个问题的一种方法是使用stream而不是Uri来初始化BitmapImage
这是适合我的版本(您的原始代码也在此处,但被注释掉了)。
var imageFile = await ApplicationData.Current.LocalFolder.CreateFileAsync(
  "test.png", CreationCollisionOption.ReplaceExisting);
/*
var fs = await imageFile.OpenAsync(FileAccessMode.ReadWrite);
DataWriter writer = new DataWriter(fs.GetOutputStreamAt(0));
writer.WriteBytes(await response.Content.ReadAsByteArrayAsync());
await writer.StoreAsync();
writer.DetachStream();
await fs.FlushAsync();
writer.Dispose();

if (Uri.TryCreate(imageFile.Path, UriKind.RelativeOrAbsolute, out imageUri))
{
    image = new BitmapImage(imageUri);
}
*/
var fs = await imageFile.OpenStreamForWriteAsync();
await response.Content.CopyToAsync(fs);
await fs.FlushAsync();
// you may want to have this Dispose as part of a 
// finally block (try/ catch/ finally)
fs.Dispose();

var bs = await imageFile.OpenAsync(Windows.Storage.FileAccessMode.Read);
image = new BitmapImage();
image.SetSource(bs);
...
image1.Source = image;

嗯,现在我在var stream = await imageFile.OpenAsync(Windows.Storage.FileAccessMode.Read);处遇到了一个UnauthorizedAccessException(访问被拒绝。(HRESULT:0x80070005(E_ACCESSDENIED)的异常))。这次可能是权限问题?有什么想法? :/ - ReignOfComputer
2
@ReignOfComputer - 请看我的更新帖子。它已经有了很大的改变。 - chue x

1
我在将PDF文档下载到本地文件夹并尝试显示时遇到了同样的问题。我无法确定为什么会发生这种情况,但是这个小技巧帮助我解决了问题:
不要使用

,而是使用。
try
{
  StorageFile storage = await ApplicationData.Current.LocalFolder.CreateFileAsync(
    fileName, CreationCollisionOption.ReplaceIfExists);

  //work with file
}
catch (Exception) { ... }

我现在使用这个:

StorageFile storage = null;
try 
{ 
  //First try to get the file
  storage = await ApplicationData.Current.LocalFolder.GetFileAsync(fileName); 
}
catch (Exception) 
{ 
  //Ignore this exception
}

try
{
  //If the storage file is still null, create it
  if (storage == null)
    storage = await ApplicationData.Current.LocalFolder.CreateFileAsync(
      fileName, CreationCollisionOption.OpenIfExists);

  //Work with file
}
catch (Exception)
{
  //Process exception
}

1
如果可以使用CreationCollisionOption.GenerateUniqueName而不是ReplaceExisting,则请尝试使用此选项。至少对于我来说,它解决了问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接