Существует ли причина, по которой Image.FromFile создает исключение OutOfMemoryException для недопустимого формата изображения? - PullRequest
27 голосов
/ 09 апреля 2010

Я пишу код, который перехватывает это 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 намеренно выбрасывается по определенной причине?

Ответы [ 4 ]

37 голосов
/ 09 апреля 2010

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

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

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

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

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)
};
7 голосов
/ 09 апреля 2010

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

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

3 голосов
/ 09 апреля 2010

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

2 голосов
/ 09 апреля 2010

Это вводящее в заблуждение исключение. Microsoft говорит :

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

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

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

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

(Растровое изображение спускается с изображения)

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

...