【问题标题】:Unable to overwrite uploaded images in C# using the Image object无法使用 Image 对象覆盖 C# 中上传的图像
【发布时间】:2009-07-30 21:58:26
【问题描述】:

我正在尝试使用 MVC 框架在 C# 中创建一个实用程序,其中用户上传一张图片,该图片用于裁剪出用作缩略图图标的图片(在任何给定的情况下,一次只有一个用户会这样做时间)。然后用户可以上传不同的图片并继续裁剪。

我有一个控制器操作来处理文件上传并拍摄照片,将其从任何格式转换为 jpeg 并将其保存为“temp.jpg”(我知道它不是一个瘦控制器,但这只是为了测试目的)。当他们上传下一张图片时,我想用这张新图片替换那个 temp.jpg。此控制器在我的机器上的开发中工作正常,但在用户上传第一张图片并尝试用另一张图片替换后的生产中,他们收到以下错误:

“该进程无法访问该文件,因为它正被另一个进程使用”

在我看来,“temp.jpg”文件在第一次上传后被锁定,我不知道如何避免这种情况。

欢迎任何建议或替代想法。

分解我的代码的作用:

  • 检查图片是否要上传 存在于服务器上,如果发现则删除它
  • 按原样保存图片 它是原始文件名和扩展名
  • 检查“temp.jpg”文件并在找到时将其删除
  • 在 System.Drawing.Image 对象中打开原始图像以转换为 jpeg
  • 将其另存为新的“temp.jpg”以替换已删除的文件。

我的代码:

        [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult PicUpload(DateTime sd, FormCollection collection)
    {
            foreach (string file in Request.Files)
            {
                HttpPostedFileBase hpf = Request.Files[file] as HttpPostedFileBase;
                    if (hpf.ContentLength == 0)
                        continue;
                    string savedFileName = Path.Combine(
                       AppDomain.CurrentDomain.BaseDirectory + "Content\\AdContent\\",
                       Path.GetFileName(hpf.FileName));

                    FileInfo temp = new FileInfo(savedFileName);
                    if (temp.Exists) temp.Delete();

                    hpf.SaveAs(savedFileName);

                    string tempFileName = AppDomain.CurrentDomain.BaseDirectory + "Content\\AdContent\\temp.jpg";

                    temp = new FileInfo(tempFileName);
                    if (temp.Exists) temp.Delete();

                    EncoderParameters codecParams = new EncoderParameters(1);
                    codecParams.Param[0] = new EncoderParameter(Encoder.Quality, 100L);
                    ImageCodecInfo[] encoders;
                    encoders = ImageCodecInfo.GetImageEncoders();

                    Image newPic = Image.FromFile(savedFileName);
                    newPic.Save(tempFileName, encoders[1], codecParams);
                    newPic.Dispose();

                    FileInfo tmp = new FileInfo(savedFileName);
                    if (tmp.Exists) tmp.Delete();
                    return RedirectToAction("Create", new { startdate = String.Format("{0:MM-dd-yyyy}", sd) });
            }
            return RedirectToAction("Create", new { startdate = String.Format("{0:MM-dd-yyyy}", sd) });
    }

【问题讨论】:

    标签: c# .net asp.net-mvc image file-io


    【解决方案1】:

    事实证明,在返回图像的宽度和高度属性的代码的另一部分中,我没有正确释放图像的资源。另外,使用Dispose(); 方法,我将代码放入“使用块”,而不是像这样:

                using (Image newPic = Image.FromFile(savedFileName))
                {
                    newPic.Save(tempFileName, encoders[1], codecParams);
                }
    

    这就像一个魅力,我现在可以毫无顾忌地删除 temp.jpg 文件。

    【讨论】:

      【解决方案2】:

      System.Drawing.Image.Save() 无法保存到打开文件的同一位置:

      来自the docs:“不允许将图像保存到构造它的同一文件中,并且会引发异常。”

      【讨论】:

      • 我不会将它保存到同一个位置。我编辑了我的问题,以使我的代码试图做的事情更清楚。简而言之,我保存文件,然后尝试创建一个名为“temp.jpg”的副本,但如果该文件已从上一次上传中锁定,我无法删除它以覆盖它。
      【解决方案3】:

      使用“面板”控件,并将其保存为 BMP、PNG 等格式

      【讨论】:

        【解决方案4】:

        您可以为tempFileName 使用唯一命名的临时文件,而不是“temp.jpg”。 System.IO.Path 有一个 GetTempFileName() 方法,您可以使用它。

        另一种选择是使用返回随机路径或文件名的GetRandomFileName() 方法(也在System.IO.Path 中),然后只需对您的代码进行一些小改动:

        - string tempFileName = AppDomain.CurrentDomain.BaseDirectory + "Content\\AdContent\\temp.jpg";
        + string tempFileName = AppDomain.CurrentDomain.BaseDirectory + "Content\\AdContent\\" + System.IO.Path.GetRandomFileName();
        

        【讨论】:

        • 这可能有效,但我必须存储文件名并让我的视图引用它。
        • 这很可能是你最终不得不做的事情。
        • 不过有一个问题,如果文件被锁定,即使我得到一个随机文件名,当我稍后在用户上传文件后尝试清理它时,该文件是否仍会被锁定具有新随机名称的新文件?
        猜你喜欢
        • 1970-01-01
        • 2021-06-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-25
        • 1970-01-01
        相关资源
        最近更新 更多