Есть ли причина Изображение. 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 намеренно будучи брошенным по конкретной причине?

27
задан Joe 17 January 2011 в 18:14
поделиться

4 ответа

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

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

Код ошибки 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)
};
37
ответ дан 28 November 2019 в 05:10
поделиться

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

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

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

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

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

(Bitmap происходит от Image)

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

2
ответ дан 28 November 2019 в 05:10
поделиться

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

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

7
ответ дан 28 November 2019 в 05:10
поделиться

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

3
ответ дан 28 November 2019 в 05:10
поделиться
Другие вопросы по тегам:

Похожие вопросы: