Подтвердить что ты не робот

Есть ли причина Image.FromFile вызывает исключение OutOfMemoryException для недопустимого формата изображения?

Я пишу код, который ловит этот OutOfMemoryException и генерирует новое, более интуитивное исключение:

/// ...
/// <exception cref="FormatException">The file does not have a valid image format.</exception>
public static Image OpenImage( string filename )
{
    try
    {
        return Image.FromFile( filename );
    }
    catch( OutOfMemoryException ex )
    {
        throw new FormatException( "The file does not have a valid image format.", ex );
    }
}

Является ли этот код приемлемым для своего пользователя или OutOfMemoryException намеренно выбрасывается по определенной причине?

4b9b3361

Ответ 1

Нет, это история. GDI + был написан довольно давно, прежде чем .NET когда-либо появлялся. Обертка SDK для него была написана на С++. Исключения в С++ есть, но не все покупают их. Google, например, не работает. Поэтому, чтобы поддерживать его совместимость, он сообщает о проблемах с кодами ошибок. Это просто никогда не масштабируется, программисты библиотеки ставят перед собой цель преднамеренно ограничить количество возможных кодов ошибок, это уменьшает нагрузку на клиента-программиста, который должен сообщить об этом.

GDI + имеет эту проблему в пиках, она определяет только 20 кодов ошибок. Это не так много для такого большого фрагмента кода с таким количеством внешних зависимостей. Что само по себе является проблемой, есть gazillion способы испортить файл изображения. Ни в коем случае сообщение об ошибках в библиотеке может быть достаточно тонким, чтобы охватить все их. Тот факт, что эти коды ошибок были выбраны задолго до того, как определенные .NET типы, основанные на исключениях, определенно не помогли.

Код ошибки Status:: OutOfMemory перегружен, что означает разные вещи. Иногда это действительно означает нехватку памяти, он не может выделить достаточно места для хранения битмартных бит. К сожалению, проблема с форматом файла изображения сообщается по тому же коду ошибки. Трение здесь заключается в том, что он не может решить, является ли ширина * высота * пикселей, которые он считывает из файла изображения, проблемой, потому что для растрового изображения недостаточно памяти. Или если данные в файле изображения неактивны. Он предполагает, что файл изображения не является нежелательным, честным вызовом, а другой проблемой программы. Итак, OOM - это то, что он сообщает.

Для полноты, это коды ошибок:

enum Status
{
    Ok = 0,
    GenericError = 1,
    InvalidParameter = 2,
    OutOfMemory = 3,
    ObjectBusy = 4,
    InsufficientBuffer = 5,
    NotImplemented = 6,
    Win32Error = 7,
    WrongState = 8,
    Aborted = 9,
    FileNotFound = 10,
    ValueOverflow = 11,
    AccessDenied = 12,
    UnknownImageFormat = 13,
    FontFamilyNotFound = 14,
    FontStyleNotFound = 15,
    NotTrueTypeFont = 16,
    UnsupportedGdiplusVersion = 17,
    GdiplusNotInitialized = 18,
    PropertyNotFound = 19,
    PropertyNotSupported = 20,
#if (GDIPVER >= 0x0110)
    ProfileNotFound = 21,
#endif //(GDIPVER >= 0x0110)
};

Ответ 2

Хорошо, это хороший пример того, как исключение не всегда означает то, что он говорит. Этот конкретный случай (OutOfMemoryException для недопустимого файла) восходит к .Net 1.0, у которого был более ограниченный набор типов исключений, из которых программисты этой библиотеки могли бы выбрать. Я предполагаю, что с тех пор он не изменился, чтобы поддерживать обратную совместимость (a.k.a. "бросать хорошие деньги после неудачи" ).

Чтобы быть справедливым, я думаю, что это был самый худший выбор для типа исключения, который они могли бы сделать здесь. Когда вы открываете файл, и он бывает большим, и вы получаете OutOfMemoryException, логично предположить, что вы на самом деле не заняты памятью и некоторое время лаете неправильное дерево (есть более одного вопроса о StackOverflow об этом).

Ответ 3

Если это связано с тем, что файл недействителен, возможно, он просто пытается угадать, насколько большой буфер нужен, основываясь на некоторых байтах в том, что, по его мнению, является заголовком. Документируйте свое намерение четко с тестом, и вы должны быть в порядке.

Ответ 4

Это ошибочное исключение. Microsoft говорит:

При попытке использовать метод Bitmap.FromFile в .NET Framework 1.0 появляется сообщение об ошибке "System.OutOfMemoryException"

Эта проблема может возникнуть, если вы используете метод Bitmap.FromFile, и выполняется одно из следующих условий:

  • Файл изображения поврежден.
  • Файл изображения является неполным.

Примечание У вас может возникнуть эта проблема, если ваше приложение пытается использовать метод Bitmap.FromFile в потоке файлов, который не завершен в файле. * Файл изображения не имеет допустимого формата изображения, или GDI + не поддерживает формат пикселя файла. * У программы нет разрешений на доступ к файлу изображения. * Свойство BackgroundImage устанавливается непосредственно из метода Bitmap.FromFile.

(Растровое изображение сходит с изображения)

Конечно, это также можно получить, если вы попытаетесь загрузить изображение, которое слишком велико. Поэтому вам нужно это учитывать.