Загрузка файла в растровое изображение с сохранением исходного файла без изменений - PullRequest
7 голосов
/ 02 августа 2010

Как это сделать в C #?

Если я использую Bitmap.FromFile (), исходный файл блокируется.

Если я использую Bitmap.FromStream (), исходный файл не блокируется, но в документации говорится: «Вы должны держать поток открытым в течение всего времени жизни изображения». Это, вероятно, означает, что файл все еще связан с объектом изображения (например, возможно, если файл изменился, измените объект или наоборот).

я хочу просто прочитать растровое изображение и сохранить его в объекте, и после этого нет никакой связи между файлом и объектом Image

Ответы [ 4 ]

26 голосов
/ 02 августа 2010

Некоторая справочная информация об этом поведении: растровое изображение использует отображенный в памяти файл для доступа к пикселям в растровом изображении.Это очень базовое средство в Windows API, оно позволяет очень эффективно отображать память для хранения данных.Данные считываются из файла только тогда, когда программа читает память, страницы виртуальной памяти не занимают места в файле подкачки Windows.

Точно такой же механизм используется для загрузки сборок .NET.Именно отображение памяти устанавливает блокировку файла.Именно поэтому сборки блокируются, когда они используются в программе .NET.Метод Image.Dispose () снимает блокировку.Борьба с блокировкой часто означает, что вы забыли избавиться от своих растровых изображений.Очень важно, забывание вызова Dispose () не часто вызывает проблемы для классов .NET, за исключением Bitmap, поскольку ему может потребоваться так много (неуправляемой) памяти.

Да, FromStream () не позволяет классу делатьэто оптимизация.Стоимость значительна, вам понадобится удвоить память при загрузке растрового изображения.Это будет проблемой, когда растровое изображение велико, вы пропускаете OOM, когда программа некоторое время работает (фрагментирует адресное пространство), и она не работает в 64-битной операционной системе.Определенно избегайте этого, если ширина растрового изображения x Высота x 4> = 45 МБ, дайте или возьмите.

Некоторый код, вам не нужно перепрыгивать через обруч CopyStream:

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

Обратите внимание, что вы не хотите утилизировать MemoryStream, вам будет сложно диагностировать «общую ошибку», когда растровое изображение будет использовано, если вы это сделаете.Вызывается ленивым чтением потока класса Image.

4 голосов
/ 02 августа 2010

Чтобы создать изображение без блокировки файла, вам нужно будет создать копию FileStream изображения.Проверьте эту страницу Лучший способ скопировать два экземпляра Stream - C # , чтобы узнать, как копировать поток.

После этого просто создайте свое изображение из скопированного потока, и вы готовы к работе.

4 голосов
/ 02 августа 2010

Считайте файл в память, скопировав его из FileStream в MemoryStream. (Ищите CopyStream в Переполнении стека, чтобы найти множество примеров того, как сделать это безопасно. По существу, цикл при чтении, запись каждого куска в поток памяти, пока нет больше данных для чтения.) Затем перемотайте MemoryStream ( установите Position = 0) и затем передайте это Bitmap.FromStream.

0 голосов
/ 25 мая 2011

Я использовал эту технику копирования в MemoryStream и затем подачи MemoryStream в Bitmap.FromStream довольно много раз. Тем не менее, есть один метод с этой техникой.

Если вы планируете использовать один из методов Bitmap.Save позже в загруженном изображении, то вам придется поддерживать поток живым (т.е. не утилизировать его после загрузки изображения), иначе вы получите Страшное исключение «Произошла общая ошибка GDI +»!

...