Loading a file to a Bitmap but leaving the original file intact

别说谁变了你拦得住时间么 提交于 2019-11-28 00:42:04

问题


How to do this in C#?

If I use Bitmap.FromFile(), the original file is locked.

If I use Bitmap.FromStream(), the original file is not locked, but the documentation says "You must keep the stream open for the lifetime of the Image." This probably means that the file is still linked to the image object, (for example, perhaps if the file change so do the object or vice versa).

what i want to do is just reading the bitmap and save it to an object and after that there is no link whatsoever between the file and the Image object


回答1:


Some background info on this behavior: Bitmap uses a memory-mapped file to access the pixels in the bitmap. That's a very basic facility in the Windows API, it allows very efficient mapping of memory to file data. Data is read from the file only when the program read the memory, the virtual memory pages don't take any space in the Windows paging file.

The exact same mechanism is used to load .NET assemblies. It is the memory mapping that puts a lock on the file. Which is basically why assemblies are locked when they are used in a .NET program. The Image.Dispose() method releases the lock. Fighting the lock often indicates that you are forgetting to dispose your bitmaps. Very important, forgetting to call Dispose() doesn't often cause problems for .NET classes, except for Bitmap since it can need so much (unmanaged) memory.

Yes, FromStream() prevents the class from making this optimization. The cost is significant, you'll need double the memory when the bitmap is loaded. This will be a problem when the bitmap is large, you're skirting OOM when the program has been running for a while (fragmenting the address space) and its not running on a 64-bit operating system. Definitely avoid doing this if the bitmap's Width x Height x 4 >= 45 MB, give or take.

Some code, you don't have to jump through the CopyStream hoop:

    public static Image LoadImageNoLock(string path) {
        var ms = new MemoryStream(File.ReadAllBytes(path)); // Don't use using!!
        return Image.FromStream(ms);
    }

Note that you don't want to dispose the MemoryStream, you'll get a hard to diagnose "generic error" when the bitmap gets used if you do. Caused by the Image class lazy-reading the stream.




回答2:


Read the file into memory by copying it from a FileStream into a MemoryStream. (Search for CopyStream in Stack Overflow to find plenty of examples of how to do that safely. Basically loop while reading, writing each chunk to the memory stream, until there's no more data to read.) Then rewind the MemoryStream (set Position = 0) and then pass that to Bitmap.FromStream.




回答3:


In order to create an image without locking the file, you'll have to create a copy of the image's FileStream. Check this page Best way to copy between two Stream instances - C# for how to copy the stream.

Afterwards just create your image from the copied stream and you're ready to go.




回答4:


I have used this technique of copying to MemoryStream and then feeding the MemoryStream to Bitmap.FromStream quite a lot of times. However, there is one gotcha with this technique as well.

If you are planning to use one of the Bitmap.Save methods later on the loaded image, then you'll have to keep the stream alive (i.e., not dispose it after the image is loaded), else you'll get the dreaded "A generic GDI+ error occurred" exception!



来源:https://stackoverflow.com/questions/3386749/loading-a-file-to-a-bitmap-but-leaving-the-original-file-intact

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!