无法访问文件,因为它被另一个进程异常使用

时间:2012-06-27 13:44:16

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

我在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-不要修改\ DATA \ 654.jpg”
它第一次工作正常,文件被复制到其目标文件夹。

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

enter image description here

我也在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;
    }

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

4 个答案:

答案 0 :(得分:4)

您应该使用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;

答案 1 :(得分:1)

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

并且,当您继续覆盖相同的目标图像名称时,代码会抛出上述异常。

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

[更新问题后编辑]

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

来自MSDN documentation

  

如果要关闭a,请将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识别出更改...; - )

答案 2 :(得分:0)

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

如果其他答案建议的延迟足以复制文件,则可能是您无法使用该工具进行检查。在这种情况下,您需要一个自动解决方案来确定锁定文件的人员。你可以使用WMI来做到这一点。

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

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

答案 3 :(得分:0)

您可以将文件加载到内存中,然后可以从内存数据中创建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