6

所以我正在使用 C# 并正在制作一个注册系统。所以有一个添加图片的选项,我做什么,我提示用户选择一个文件,然后该文件将被复制到目录文件夹,然后重命名为学生的录取编号。这是该浏览按钮的代码:

OpenFileDialog openDlg = new OpenFileDialog();
            openDlg.Filter = "All JPEG files (*.jpg; *.jpeg)| *.jpg; *.jpeg";
            string filter = openDlg.Filter;
            openDlg.Multiselect = false;
            openDlg.Title = "Open a JPG File";
            if (openDlg.ShowDialog() == DialogResult.OK)
            {                
                curFileName = openDlg.SafeFileName;
                string curFilePath = openDlg.FileName;

                openDlg.Dispose();

                string sourcePath = @curFilePath.Remove((curFilePath.Length - curFileName.Length));
                string targetPath = "@";

                mycon.Open();
                string cmdstr = "SELECT imageDirectory from userSettings WHERE ID = 1";
                cmd = new OleDbCommand(cmdstr, mycon);
                dr = cmd.ExecuteReader();
                while (dr.Read())
                {
                    targetPath = (@dr["imageDirectory"].ToString());
                }
                dr.Close();
                mycon.Close();

                string sourceFile = Path.Combine(sourcePath, curFileName);
                string destFile = Path.Combine(targetPath, curFileName);

                File.Copy(sourceFile, destFile, true);

                newname = @destFile.Remove((destFile.Length - curFileName.Length)).ToString() + "\\" + (DateTime.Now.Year + "-" + textBox1.Text+".jpeg");

                if (File.Exists(newname) == true)
                {
                    pictureBox1.Image.Dispose();
                    try
                    {
                        File.Delete(newname);
                    }

                    catch (IOException ex)
                    {
                        MessageBox.Show(ex.ToString());
                        return;
                    }
                }

                File.Move(destFile, newname);

                photoPath = newname;
                pictureBox1.Image = Image.FromFile(photoPath);

问题是:

a.) 我有一个功能允许用户进入下一步,然后如果他想在最后一步进行一些更改,他可以返回并更新它。这里的问题是当他更改图片时,我收到一条错误消息“无法访问该文件,因为它正在被另一个进程使用”

b.) 当用户已经上传了一张图片,然后返回主页,他决定重新注册时将无法上传新的图片,并且错误提示:“无法访问文件,因为它正被另一个进程使用”。

这两个错误都指向这里:

`File.Delete(newname);`

我真的不知道该怎么做伙计们,我从昨晚开始就一直在寻找解决方案,但我看不到一个不会让我完全改变整个代码的解决方案。请帮忙 :(

4

2 回答 2

8

您的代码是正确的,请忽略有关代码气味的贬低。处理 PictureBox.Image 对于避免内存不足异常很重要。

此问题是由 Bitmap 类的实现细节引起的。当您打开图像文件时,该类会创建一个内存映射文件以将图像的像素数据映射到内存中。这是对大图像的重要优化,它将像素数据保留在页面文件之外。现在它已经不那么重要了,在 GDI+ 设计 15 年后,现代机器拥有大量 RAM 和磁盘空间。

但是,该内存映射文件会在该文件上创建一个锁。重要的是要防止任何其他进程弄乱文件数据并使文件的映射视图无效。这就是您所看到的,尝试替换或删除文件不再有效。您可以通过创建位图的深层副本来避免这种情况,该副本在内存中包含所有像素数据并且不再使用该文件。像这样:

public static Bitmap LoadBitmapNolock(string path) {
    using (var img = Image.FromFile(path)) {
        return new Bitmap(img);
    }
}

Do note that the odds of running out of memory with large images on a 32-bit version of Windows is significantly increased with this code.

于 2012-10-14T10:21:46.083 回答
1

.Dispose()在托管语言(如 C#)中手动使用是Code Smell。您可能最终处于某种无效状态,因为您正在尝试手动管理资源。您可以避免这种情况的两种方法是:

  1. 摆脱不需要的.Dispose()元素(如opnDlg.Dispose()),和/或
  2. 尝试将需要处理的对象包装在using(...){...}语句中

无论哪种方式,一旦你重构了你的代码,就不应该有任何.Dispose()方法调用。您正在使用的对象要么不需要手动管理,并且尝试这样做只会导致问题,要么它们绝对需要管理,因此该using(...)语句要优越得多,因为它保证在何时释放资源退出代码块。

于 2012-10-14T06:17:07.600 回答