将文件加载到位图但保留原始文件

时间:2010-08-02 10:11:09

标签: c# .net image system.drawing

如何在C#中执行此操作?

如果我使用Bitmap.FromFile(),原始文件将被锁定。

如果我使用Bitmap.FromStream(),原始文件不会被锁定,但文档说“你必须在图像的生命周期内保持流打开”。这可能意味着文件仍然链接到图像对象(例如,如果文件更改,则对象反之亦然)。

我想要做的只是读取位图并将其保存到对象中,之后文件和Image对象之间没有任何链接

4 个答案:

答案 0 :(得分:26)

此行为的一些背景信息:位图使用内存映射文件来访问位图中的像素。这是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,如果您使用位图,则很难诊断出“一般错误”。由Image类引起的懒惰读取流。

答案 1 :(得分:4)

将文件从FileStream复制到MemoryStream,将文件读入内存。 (在Stack Overflow中搜索CopyStream以找到大量如何安全地执行此操作的示例。基本上在读取时循环,将每个块写入内存流,直到没有更多数据要读取。)然后回退{{ 1}}(设置MemoryStream),然后将其传递给Position = 0

答案 2 :(得分:4)

为了在不锁定文件的情况下创建图像,您必须创建图像的FileStream的副本。 请查看此页Best way to copy between two Stream instances - C#以了解如何复制流。

之后只需从复制的流中创建您的图像,您就可以开始使用了。

答案 3 :(得分:0)

我已经使用这种复制到MemoryStream的技术,然后将MemoryStream很多次送到Bitmap.FromStream。然而,这种技术也有一个问题。

如果您计划稍后在加载的图像上使用其中一个Bitmap.Save方法,那么您必须保持流存活(即,在加载图像后不将其丢弃),否则您将获得可怕的“一般GDI +错误发生”例外!

相关问题