为什么PictureBox.Load在某些系统上锁定图像?

use*_*589 5 c# bitmap file-locking picturebox winforms

(如果您不想阅读整个故事,请参阅问题底部的编辑.)

嗨,

我是stackoverflow的新手.不要误会我的意思,我经常使用它.但到目前为止,我从未真正发布过一些东西.这是因为我没有新的/有用的东西说,我的英语不是那么好.第一件事(可能)改变了,后者没改变.

我最近在客户的Windows 7系统上遇到了问题.我通过ClickOnce发布了一个C#.Net 4.0 Windows Forms应用程序.基本上,它是一个创建位图文件并将其显示给用户的应用程序.如果在创建之前存在位图,则首先删除现有文件.之后,新文件由PictureBox创建和加载.

客户系统发生以下情况:启动应用程序后,第一次创建成功 - 第二次创建成功,后续所有创建成功.该文件无法删除,因为某些进程阻止了该文件.这个过程就是应用程序本身.

System.IO.IOException:进程无法访问文件"filename",因为它正由另一个进程使用.

嗯,当然这没什么不寻常的.问题是我在几个系统上测试了应用程序.没有显示此例外.到目前为止,我无法看到代码错误.

所以我在客户的系统上看得更近了一点:我唯一能看到的是,他们改变了用户文件夹,使它们不在Windows分区上,而是在另一个分区上(C:\ Users - > d:\用户).我在互联网上搜索了一条指令,并在我的一个测试系统上做了同样的事情.令我惊讶的是,当我运行我的应用程序时,我遇到了同样的异常.

有了这个,我可以改变我的代码,以便不再发生异常.但我不明白为什么会这样.所以也许我的代码有问题,而错误只是在这种特殊情况下揭示出来.或者代码可以正常,原因在于其他地方.我只是希望你能帮助我.

所以这里是我放在一起的一些代码,它们显示了相同的行为.我在Form上使用了3个按钮,一个OpenFileDialog和一个PictureBox.首先要做的是选择一个图像文件.通过按其余两个按钮之一,它将被复制到应用程序的主文件夹中.复制后,它由PictureBox显示.顺便说一句,它是ClickOnce应用程序还是"普通"应用程序似乎并不重要.

String m_FileName;

private void btnChooseFile_Click(object sender, EventArgs e) {
    if(openFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK) { // If file was chosen, set file name for later use and activate buttons.
        m_FileName = "Test" + Path.GetExtension(openFileDialog1.FileName);
    }
}

private void button1_Click(object sender, EventArgs e) {

    // This is not working.
    if(this.pictureBox1.Image != null) {
        //Image img = this.pictureBox1.Image; // I was not sure, if maybe the pictureBox somehow prevents the disposing of the image, as long as it's assigned to it.
        //this.pictureBox1.ImageLocation = null; // So I set them null, both the image and the image location.
        //this.pictureBox1.Image = null; 
        //img.Dispose(); // Then I disposed the image.

        this.pictureBox1.Image.Dispose(); // The short version. It is not working either way.
        this.pictureBox1.Image = null;
    }
    (new FileInfo(openFileDialog1.FileName)).CopyTo(m_FileName, true); // But still this is where the Exception occurs.
    this.pictureBox1.Load(m_FileName);
}

private void button2_Click(object sender, EventArgs e) {

    //This is working.
    if(this.pictureBox1.Image != null) {
        //Image img = this.pictureBox1.Image;
        //this.pictureBox1.Image = null;
        //img.Dispose();

        this.pictureBox1.Image.Dispose();
        this.pictureBox1.Image = null;
    }
    (new FileInfo(openFileDialog1.FileName)).CopyTo(m_FileName, true);
    pictureBox1.Image = Image.FromFile(m_FileName);
}
Run Code Online (Sandbox Code Playgroud)

现在发生的情况如下:如果我启动应用程序并单击button1两次,我将获得异常(在第二次单击时).如果我启动它并单击button2两次,我就不会.如果我启动应用程序并首先单击buttons1,然后单击button2,我将获得异常.所以,Picture.Load-Function以某种方式阻止文件,即使我处理它.

当我在互联网上搜索时,我发现了一篇来自微软的文章:http://support.microsoft.com/kb/309482/en-us.但它没有触及牛眼.

请注意,两个版本都在我的所有测试机器上运行.当我将users文件夹更改为非Windows分区时,我只是得到了异常.

这是为什么?这些版本的差异在哪里?


编辑

好吧,由于到目前为止的第一个也是唯一的反应,在我看来,它仍然不清楚,究竟发生了什么:如果我采用上面的代码,将它放在Windows窗体应用程序中,编译它并在不同的上运行它计算机(在工作中,在家里,无关紧要)它的工作原理 - button1和button2(链接到它们的Click函数)可以随意使用 - 没有异常抛出.如果我在计算机上运行应用程序,我更改了用户文件夹,然后第二次单击button1 - bam - IOException,文件被进程锁定.只要我不按button1,Button2就可以工作.

第一个答案暗示,我应该锁定每个系统.但我不(只要我不更改用户文件夹)!我在每台可以接触到的计算机上测试过它 - 没有IOException.我设置了一个新系统,只是为了排除我公司系统的一些特殊变化 - 都是buttonx_Click函数工作 - 也没有例外.我甚至在另一台计算机上编译了程序 - 同样的行为.抛出该异常的唯一三个系统是具有已更改用户文件夹的系统.

到目前为止,我不知道为什么会出现这种行为上的差异.有人能帮助我吗?

任何人?

Han*_*ant 7

是的,这很正常.发生在任何操作系统上,与Users文件夹位置无关.所述PictureBox.Load()方法intented被用来从位置加载的图像的其他比文件系统.就像一个网站.这很慢,它避免了在下载过程中冻结UI.

它在内部使用FileStream,当它发现您传递的URL实际上是文件而不是网站名称.在放置PictureBox本身或再次调用Load()方法之前,此FileStream不会被释放.一个要求,因为Image.FromStream()要求流在不再使用图像之前保持可读性.正是这个FileStream保持对文件的锁定.处置PictureBox.Image还不足以配置FileStream,Image对象不知道它正在显示在图片框内.

有几种方法可以解决这个问题:

  • 使用Image属性而不是Load(),从Image.FromFile()中分配它.现在处理图像也会释放文件上的锁定.你发现了
  • 保持虚拟图像,可能显示"正在加载..."位图.首先加载()它以释放文件上的锁
  • 处理PictureBox并重新创建它.