C# 上载的文件在被GDI读取后被锁定

C# 上载的文件在被GDI读取后被锁定,c#,io,gdi,C#,Io,Gdi,我有以下ImageObject类: public class ImageObject { public static Image CropImage(Image img, Rectangle cropArea) { Bitmap bmpImage = new Bitmap(img); Bitmap target = new Bitmap(cropArea.Width, cropArea.Height); using(Graphics

我有以下ImageObject类:

public class ImageObject
{
    public static Image CropImage(Image img, Rectangle cropArea)
    {
        Bitmap bmpImage = new Bitmap(img);
        Bitmap target = new Bitmap(cropArea.Width, cropArea.Height);
        using(Graphics g = Graphics.FromImage(target))
        {
            g.DrawImage(bmpImage, new Rectangle(0, 0, target.Width, target.Height), cropArea, GraphicsUnit.Pixel);
            g.Dispose();
        }
        return (Image)target;
    }

    public static Image ResizeImage(Image imgToResize, Size size)
    {
        int sourceWidth = imgToResize.Width;
        int sourceHeight = imgToResize.Height;

        float nPercent = 0;
        float nPercentW = 0;
        float nPercentH = 0;

        nPercentW = ((float)size.Width / (float)sourceWidth);
        nPercentH = ((float)size.Height / (float)sourceHeight);

        if (nPercentH < nPercentW)
            nPercent = nPercentH;
        else
            nPercent = nPercentW;

        int destWidth = (int)(sourceWidth * nPercent);
        int destHeight = (int)(sourceHeight * nPercent);

        Bitmap b = new Bitmap(destWidth, destHeight);
        //Graphics g = Graphics.FromImage((Image)b);
        using(Graphics g = Graphics.FromImage((Image)b))
        {
            g.InterpolationMode = InterpolationMode.HighQualityBicubic;
            g.DrawImage(imgToResize, 0, 0, destWidth, destHeight);
            g.Dispose();    
        }
        return (Image)b;
    }

    public static void SaveJpeg(string path, System.Drawing.Image source, long quality)
    {
        EncoderParameter qualityParam = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, quality);
        ImageCodecInfo jpegCodec = GetEncoderInfo("image/jpeg");
        if (jpegCodec == null)
            return;
        EncoderParameters encoderParams = new EncoderParameters(1);
        encoderParams.Param[0] = qualityParam;
        source.Save(path, jpegCodec, encoderParams);
    }

    private static ImageCodecInfo GetEncoderInfo(string mimeType)
    {
        // Get image codecs for all image formats
        ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();

        // Find the correct image codec
        for (int i = 0; i < codecs.Length; i++)
            if (codecs[i].MimeType == mimeType)
                return codecs[i];
        return null;
    }
}
此方法由web服务调用。在第一次执行此代码时(IIS重新启动后),一切正常,但如果再次使用,它将挂起。我知道这与我创建的两个图像有关:
avatar.jpg
avatar\u t.jpg
。我知道这一点,因为我无法在资源管理器中删除或重命名图像:

我已经确保按照许多人的建议处置了
图形
对象,但我不明白为什么锁不会释放?有人看到问题了吗

理想情况下,我希望在底部这样做:

var resize_twentyfive = ImageObject.ResizeImage(System.Drawing.Image.FromFile(temp_path), twentyfive);
            ImageObject.SaveJpeg(small, resize_twentyfive, 100L);

//clean up, delete avatar.jpg and avatar_t.jpg
File.Delete(temp_path);
File.Delete(full_path);
删除我以前读过的图片——它们不再需要了。我不介意它们留在那里,只要我可以在上传程序中随意覆盖它们…

在您调用图像上的Dispose之前不会关闭文件

:

当位图对象或图像对象是由 文件,则该文件在对象的生存期内保持锁定。作为一个 因此,您无法更改图像并将其保存回同一文件 它起源于哪里

此外,如果流在生命周期内被破坏 位图对象,则无法成功访问基于 在小溪上。例如,Graphics.DrawImage()函数可能不会 在流被破坏后成功

Image.FromFile()。问题是由以下原因引起的:

GDI+,因此System.Drawing命名空间,可能会延迟 对原始图像位进行解码,直到图像需要这些位为止。 此外,即使在图像被解码之后,GDI+也可能会丢失 确定丢弃大容量内存更有效 位图,以便稍后重新解码。因此,GDI+必须能够访问 位图或图像生命周期内图像的源位 反对

为了保留对源位的访问,GDI+锁定任何源文件,并且 强制应用程序维护任何源流的生命周期,例如 位图或图像对象的寿命

再次引用支持文章:

要解决此问题,请使用以下方法之一创建新位图图像: 以下方法(如本节下文所述):

  • 创建非索引图像
  • 创建索引图像
在这两种情况下,都需要对原始文件调用Bitmap.Dispose()方法 位图删除文件上的锁定或删除以下要求: 流或内存保持活跃

在对映像调用Dispose之前,不会关闭文件

:

当位图对象或图像对象是由 文件,则该文件在对象的生存期内保持锁定。作为一个 因此,您无法更改图像并将其保存回同一文件 它起源于哪里

此外,如果流在生命周期内被破坏 位图对象,则无法成功访问基于 在小溪上。例如,Graphics.DrawImage()函数可能不会 在流被破坏后成功

Image.FromFile()。问题是由以下原因引起的:

GDI+,因此System.Drawing命名空间,可能会延迟 对原始图像位进行解码,直到图像需要这些位为止。 此外,即使在图像被解码之后,GDI+也可能会丢失 确定丢弃大容量内存更有效 位图,以便稍后重新解码。因此,GDI+必须能够访问 位图或图像生命周期内图像的源位 反对

为了保留对源位的访问,GDI+锁定任何源文件,并且 强制应用程序维护任何源流的生命周期,例如 位图或图像对象的寿命

再次引用支持文章:

要解决此问题,请使用以下方法之一创建新位图图像: 以下方法(如本节下文所述):

  • 创建非索引图像
  • 创建索引图像
在这两种情况下,都需要对原始文件调用Bitmap.Dispose()方法 位图删除文件上的锁定或删除以下要求: 流或内存保持活跃


你能检查异常被抛出的确切位置吗?在第二次执行代码时,它到达
ImageObject.SaveJpeg(temp_path,crapped,100L);
并抛出一个
GDI+
异常中发生的一般错误。你能检查异常被抛出的确切位置吗?在第二次执行代码时,它到达
ImageObject.SaveJpeg(临时路径,裁剪,100L)
并抛出一个发生在GDI+
异常中的
一般错误。这是一个伟大的Mitch,当然也解释了我为什么会有这个问题。不幸的是,它没有说明如何修复它。我是否重新编写代码以不使用这些API?我会完全避免GDI吗?啊,对不起,米奇,你好像和我一样在写作。我的错误。感谢您的帮助+1。我在我的
source.Save(路径、jpegCodec、encoderParams)之后添加了
source.Dispose()
行在
SaveJpeg()
中,一切都很好。非常感谢米奇-你不仅提供了答案,还解释了问题发生的原因:)非常感谢。这是伟大的米奇,当然也解释了我为什么会有问题。不幸的是,它没有说明如何修复它。我是否重新编写代码以不使用这些API?我会完全避免GDI吗?啊,对不起,米奇,你好像和我一样在写作。我的错误。感谢您的帮助+1。我在我的
source.Save(路径、jpegCodec、encoderParams)之后添加了
source.Dispose()
行在
SaveJpeg()
中,一切都很好。马斯
var resize_twentyfive = ImageObject.ResizeImage(System.Drawing.Image.FromFile(temp_path), twentyfive);
            ImageObject.SaveJpeg(small, resize_twentyfive, 100L);

//clean up, delete avatar.jpg and avatar_t.jpg
File.Delete(temp_path);
File.Delete(full_path);