Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

File.Delete failing when Image.FromFile was called prior it, despite making copy of loaded image and destroying original one

UPDATED

I used below solutions (loading Image from stream), but get new problem. img object is absolutely correct Image class instance with all field filled with correct values. But calling

img.Save("path/to/new/image.bmp");

on it results in new exception for GDI+ (System.Runtime.InteropServices.ExternalException, in GDI+ interface) - I get error message but is in polish, am not sure how to translate it.

Original question

I have problem with C# .NET Framework 2.0

Basically I'am trying to achieve:

Image img = Image.FromFile("Path/To/Image.bmp");
File.Delete("Path/To/Image.bmp"); // Exception, the file is in use!

It is important for me to keep copy of image in memory when original file was deleted. I though it is somehow odd that .NET still lock file on hard disc despite it is no longer required for any operation (entire image is now in memory, isn't it?)

So I tried this solution:

Image img = new Image(Image.FromFile("Path/To/Image.bmp")); // Make a copy
                    // this should immiedietaly destroy original loaded image
File.Delete("Path/To/Image.bmp"); // Still exception: the file is in use!

I can do:

Image img = null;
using(Image imgTmp = Image.FromFile("Path/To/Image.bmp"))
{
    img = new Bitmap(imgTmp.Width, imgTmp.Height, imgTmp.PixelFormat);
    Graphics gdi = Graphics.FromIage(img);
    gdi.DrawImageUnscaled(imgTmp, 0, 0);
    gdi.Dispose();
    imgTmp.Dispose(); // just to make sure
}
File.Delete("Path/To/Image.bmp"); // Works fine
// So I have img!

But this seems to me almost like using nuke to kill bug... and raises another problem: GDI poorly support Drawing palette-based images onto each other (and palette ones are majority in my collection).

Am I doing something wrong? Is any better way to have Image in memory and original file deleted from hard disk?

like image 639
PiotrK Avatar asked Sep 07 '10 19:09

PiotrK


2 Answers

Your problem is that the new Image still knows where it came from, having been given the file handle from the old Image's copy constructor, and so the runtime still knows it has an open handle to the file.

You might be able to work around this behavior with a Stream instead:

Image image;
FileStream myStream = new FileStream(path);

try
{
    image = Image.FromStream(myStream);
}
finally
{    
    myStream.Close();
    myStream.Dispose();
}

//test that you have a valid Image and then go to work.

Here's a cleaner version with a using clause:

Image image;
using(FileStream myStream = new FileStream(path))
{
    image = Image.FromStream(myStream);
}
//a using clause calls Dispose() at the end of the block,
//which will call Close() as well

Caveat emptor; I have not tested this, no guarantee that it'll solve the problem, but this seems reasonable. Working directly with the Stream gives you, and not the image implementation, control over the file handle, so you can make sure your program releases resources when YOU want.

like image 198
KeithS Avatar answered Oct 03 '22 21:10

KeithS


as share other way

try
{
var img = Image.FromFile(s);
var bmp = new Bitmap(img);
img.Dispose();
File.Delete(s);
}
catch { }
like image 25
farshad saeidi Avatar answered Oct 03 '22 21:10

farshad saeidi