【问题标题】:File cannot be accessed because it is used by another process exception文件无法访问,因为它被另一个进程异常使用
【发布时间】:2012-06-27 13:44:15
【问题描述】:

我正在 WPF 应用程序中执行图像读取/复制操作。请看以下代码:

try
{
  if (sourceDir != "")
    File.Copy(sourceDir, Path.Combine(backupDir, ecode + ".jpg"), true);
}
catch (Exception exx)
{
    MessageBox.Show(exx.ToString());
}

现在让我们用一个场景来解释问题:
第一次执行此代码时,sourceDirPath.Combine(backupDir, ecode + ".jpg") 值是:
sourceDir="C:\Users\Public \Pictures\Sample Pictures\Desert.jpg"
Path.Combine(backupDir, ecode + ".jpg")="D:\IEPL-archives-Do not Modify\DATA\654. jpg"
它第一次工作正常,文件被复制到其目标文件夹。

但是第二次使用以下值执行此代码时:
sourceDir="C:\Users\Public\Pictures\Sample Pictures\Penguins.jpg"
Path。 Combine(backupDir, ecode + ".jpg")="D:\IEPL-archives-不要修改\DATA\654.jpg"
它抛出以下异常:

我也在 UI 中显示相同的图像,这导致了这个异常。这是在 UI 中显示图像的代码:

image1.Source = new BitmapImage(new Uri(GetPicture(txtBarcode.Text), UriKind.RelativeOrAbsolute));
private string GetPicture(string _eid)
    {
        string picname = "";
        if (File.Exists(@"D:\IEPL-archives-Do not Modify\DATA\" + _eid + ".jpg"))
            picname = @"D:\IEPL-archives-Do not Modify\DATA\" + _eid + ".jpg";
        else if (File.Exists(@"D:\IEPL-archives-Do not Modify\DATA\" + _eid + ".jpeg"))
            picname = @"D:\IEPL-archives-Do not Modify\DATA\" + _eid + ".jpeg";
        else if (File.Exists(@"D:\IEPL-archives-Do not Modify\DATA\" + _eid + ".png"))
            picname = @"D:\IEPL-archives-Do not Modify\DATA\" + _eid + ".png";
        else if (File.Exists(@"D:\IEPL-archives-Do not Modify\DATA\" + _eid + ".gif"))
            picname = @"D:\IEPL-archives-Do not Modify\DATA\" + _eid + ".gif";
        else if (File.Exists(@"D:\IEPL-archives-Do not Modify\DATA\" + _eid + ".JPG"))
            picname = @"D:\IEPL-archives-Do not Modify\DATA\" + _eid + ".JPG";
        else if (File.Exists(@"D:\IEPL-archives-Do not Modify\DATA\" + _eid + ".JPEG"))
            picname = @"D:\IEPL-archives-Do not Modify\DATA\" + _eid + ".JPEG";
        else if (File.Exists(@"D:\IEPL-archives-Do not Modify\DATA\" + _eid + ".PNG"))
            picname = @"D:\IEPL-archives-Do not Modify\DATA\" + _eid + ".PNG";
        else if (File.Exists(@"D:\IEPL-archives-Do not Modify\DATA\" + _eid + ".GIF"))
            picname = @"D:\IEPL-archives-Do not Modify\DATA\" + _eid + ".GIF";
        else
            picname = @"Images\defaultPicture.jpg";
        return picname;
    }

请建议我如何修改代码以免出现这种冲突? 谢谢

【问题讨论】:

  • 图像(D:\IEPL-archives-Do not Modify\DATA\654.jpg)是否显示在 UI 中?
  • @ekholm 是的,此图像同时显示在 UI 中。
  • Path.Combine(backupDir, ecode + ".jpg") 都具有相同的目标图像位置。这是故意的吗?如果没有,那可能已经是您异常的原因了...
  • @JensH 我明白你的意思。我还必须在 UI 上显示图片,我正在使用以下代码:image1.Source = new BitmapImage(new Uri(GetPicture(txtBarcode.Text), UriKind.RelativeOrAbsolute));

标签: c# wpf visual-studio image file-io


【解决方案1】:

您应该使用BitmapCacheOption.OnLoad 将图像加载到内存中。这将释放对文件的锁定。

BitmapImage bi = new BitmapImage();
bi.BeginInit();

bi.CacheOption = BitmapCacheOption.OnLoad;
bi.UriSource = new Uri(GetPicture(txtBarcode.Text), UriKind.RelativeOrAbsolute);

// End initialization.
bi.EndInit();
image1.Source = bi;

【讨论】:

  • 使用此代码更新后现在没有例外,但图像文件没有被更新/替换为新的!
  • 看不到为什么使用新的源路径调用 File.Copy 时图像文件没有被替换,并且没有引发异常。你确定吗?
  • 如果您的意思是 UI 中的图像没有更新,这是正常的。您需要重新加载它。
  • @ekholm 我的错!!此代码完美运行。实际上,Windows 没有更新目标文件夹中的图像缩略图,这就是我假设图像没有更新的原因。但是当我打开一张图片时,它就是里面需要的图片(但缩略图不同)。你能告诉我为什么会这样吗?
  • 文件夹中图像的缩略图被缓存并映射到文件名,并且显然不会在这种文件访问时自动重新加载。很高兴你让它工作了!
【解决方案2】:

根据之前的 cmets,可能是文件句柄在 UI 中显示后保持打开状态。所以我猜在你第一次复制它然后显示它之后,句柄可能永远不会关闭。

而且,当您不断覆盖相同的目标图像名称时,代码会引发上述异常。

例如,如果您使用的是Image.FromFile()methood,情况正是如此。这确实使句柄保持打开状态,直到应用程序结束...

[更新问题后编辑]

您需要将缓存选项更改为:

来自MSDN documentation

如果你想关闭一个缓存选项,请将 CacheOption 设置为 BitmapCacheOption.OnLoad 用于创建 BitmapImage 的流。默认 OnDemand 缓存 选项保留对流的访问,直到需要图像,并且 清理由垃圾收集器处理。

(从文档中复制的代码。)

// Define a BitmapImage.
Image myImage = new Image();
BitmapImage bi = new BitmapImage();

// Begin initialization.
bi.BeginInit();

// Set properties.
bi.CacheOption = BitmapCacheOption.OnLoad; // <-- This is the important one
bi.CreateOptions = BitmapCreateOptions.DelayCreation;
bi.DecodePixelHeight = 125;
bi.DecodePixelWidth = 125;
bi.Rotation = Rotation.Rotate90;
MessageBox.Show(bi.IsDownloading.ToString());
bi.UriSource = new Uri("smiley.png", UriKind.Relative);

// End initialization.
bi.EndInit();
myImage.Source = bi;
myImage.Stretch = Stretch.None;
myImage.Margin = new Thickness(5);

加载图像后,不要忘记抛出NotifyPropertyChanged 事件,WPF 会识别更改... ;-)

【讨论】:

    【解决方案3】:

    我认为第一步是确定哪个进程锁定了您的文件。为此,我建议使用Handle from Sysinternals。一旦出现异常,请使用该应用进行检查。

    如果其他答案建议的延迟足以复制文件,则可能是您无法真正使用该工具进行检查。在这种情况下,您需要一个自动化的解决方案来确定谁在锁定文件。您可以使用 WMI 来执行此操作。

    现在,我的猜测是您的进程正在锁定文件,这意味着来自File.Copy的某种错误或意外行为。

    编辑:好的,现在我们知道您是打开文件的人...

    【讨论】:

      【解决方案4】:

      您可以将文件加载到内存中,然后可以从内存中的数据创建 BitmapImage。

          BitmapImage GetImage( String filepath)
          {
              byte[] rawImageBytes = File.ReadAllBytes(filepath);
              BitmapImage imageSource = null;
      
              try
              {
                  using ( MemoryStream stream = new MemoryStream( rawImageBytes  ) )
                  {
                      stream.Seek( 0, SeekOrigin.Begin );
                      BitmapImage b = new BitmapImage();
                      b.SetSource( stream );
                      imageSource = b;
                  }
              }
              catch ( System.Exception ex )
              {
              }
      
              return imageSource;
          }
      

      字节数组到BitmapImage的代码取自this SO question

      【讨论】:

        猜你喜欢
        • 2015-10-24
        • 2018-10-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-03-27
        相关资源
        最近更新 更多