如何在C#中执行此操作?将文件加载到位图,但保留原始文件不变
如果我使用Bitmap.FromFile(),原始文件被锁定。
如果我使用Bitmap.FromStream(),原始文件未被锁定,但文档中显示“您必须保持流在图像的整个生命周期内都处于打开状态”。这可能意味着该文件仍然与图像对象相关联(例如,如果文件改变了,对象反之亦然)。
我想要做的就是阅读的位图,并将其保存到对象后,有文件和图像目标之间没有任何联系
如何在C#中执行此操作?将文件加载到位图,但保留原始文件不变
如果我使用Bitmap.FromFile(),原始文件被锁定。
如果我使用Bitmap.FromStream(),原始文件未被锁定,但文档中显示“您必须保持流在图像的整个生命周期内都处于打开状态”。这可能意味着该文件仍然与图像对象相关联(例如,如果文件改变了,对象反之亦然)。
我想要做的就是阅读的位图,并将其保存到对象后,有文件和图像目标之间没有任何联系
有关此行为的一些背景信息:Bitmap使用内存映射文件访问位图中的像素。这是Windows API中非常基本的工具,它可以非常有效地将内存映射到文件数据。仅当程序读取内存时才从文件读取数据,虚拟内存页面不会在Windows分页文件中占用任何空间。
完全相同的机制用于加载.NET程序集。内存映射会对文件进行锁定。这基本上是为什么在.NET程序中使用程序集时它们被锁定的原因。 Image.Dispose()方法释放锁。对抗锁通常意味着你忘记处理你的位图。非常重要的是,忘记调用Dispose()通常不会导致.NET类的问题,除了Bitmap,因为它可能需要很多(非托管)内存。
是的,FromStream()阻止类进行优化。成本很高,在加载位图时需要加倍的内存。当位图很大时,这是一个问题,当程序运行了一段时间(碎片化地址空间)并且它不在64位操作系统上运行时,您正在避开OOM。绝对避免这样做,如果位图的宽度x高度x 4> = 45 MB,给予或采取。
一些代码,你不必通过CopyStream箍跳:
public static Image LoadImageNoLock(string path) {
var ms = new MemoryStream(File.ReadAllBytes(path)); // Don't use using!!
return Image.FromStream(ms);
}
注意,你不想处置的MemoryStream,你会得到一个难以诊断的“一般错误”当位图得到使用时,如果你这样做。由懒惰阅读流的图像类引起的。
通过从FileStream
将其复制文件读入到内存变成MemoryStream
。 (在堆栈溢出中搜索CopyStream
以查找大量如何安全执行的示例。基本上在读取时循环,将每个块写入内存流,直到没有更多数据可读。)然后倒回MemoryStream
(设置为Position = 0
)和然后将其传递给Bitmap.FromStream
。
为了在不锁定文件的情况下创建图像,您必须创建图像的FileStream副本。 查看此页面Best way to copy between two Stream instances - C#了解如何复制流。
之后,只需从复制的流创建图像,然后就可以开始了。
+1为我们寻找乔恩建议我们应该做的事情......你找到了一个非常好的职位。 – awe 2010-08-02 11:05:13
我已经使用这种技术复制到MemoryStream,然后将MemoryStream提供给Bitmap.FromStream很多次。但是,这种技术也有一个问题。
如果您计划稍后在加载的图像上使用其中一种Bitmap.Save方法,则必须保持该流处于活动状态(即,,不会在图像加载后进行处理),否则您将遇到可怕的“出现通用GDI +错误”异常!
你也需要这个来获取位图。位图位图=新的位图(LoadImageNoLock(路径)); – Harris 2015-01-28 09:13:38
MemoryStream是一次性的,谁会照顾在此解决方案中处理? – kwesolowski 2015-02-04 09:48:07