问题
I am writing code that catches this OutOfMemoryException
and throws a new, more intuitive exception:
/// ...
/// <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 );
}
}
Is this code acceptable to its user, or is OutOfMemoryException
intentionally being thrown for a particular reason?
回答1:
No, it is history. GDI+ was written quite a while before .NET ever came around. The SDK wrapper for it was written in C++. Exceptions are iffy in C++, not everybody buys into them. Google doesn't for example. So to keep it compatible it reports problems with error codes. That just never scales well, library programmers make it a goal to intentionally limit the number of possible error codes, it lessen the burden on the client programmer having to report them.
GDI+ has this problem in spades, it defines only 20 error codes. That is not much for such a large chunk of code with so many external dependencies. Which in itself is a problem, there are a gazillion ways to mess up an image file. No way that a library's error reporting can be fine-grained enough to cover them all. The fact that these error codes were picked long before .NET defined standard Exception derived types certainly didn't help.
The Status::OutOfMemory error code got overloaded to mean different things. Sometimes it really does mean out of memory, it can't allocate enough space to store the bitmap bits. Sadly, an image file format problem is reported by the same error code. The friction here is that it cannot possibly decide if the width * height * pixels it read from the image file is a problem because there isn't enough storage available for the bitmap. Or if the data in the image file is junk. It assumes that image file is not junk, fair call, that's another program's problem. So OOM is what it reports.
For completeness, these are the error codes:
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:
Well, it's a good example of how an exception doesn't always mean what it says. This particular case (OutOfMemoryException
for an invalid file) dates back to .Net 1.0, which had a more limited set of exception types from which the programmers of this library could choose. I assume it hasn't been changed since then to maintain backwards compatibility (a.k.a. "throwing good money after bad").
To be fair, I think it was about the worst possible choice for exception type they could have made here. When you open a file, and it happens to be big, and you get an OutOfMemoryException
, it's logical to assume that you're actually out of memory and go barking up the wrong tree for awhile (there's more than one question on StackOverflow about this).
回答3:
If it's because the file is invalid, it's probably just trying to guess how big a buffer it needs based on some bytes in what it thinks is the header. Document your intent clearly with a test and you should be fine.
回答4:
It's a misleading exception. Microsoft says:
You receive a "System.OutOfMemoryException" error message when you try to use the Bitmap.FromFile method in the .NET Framework 1.0
This problem may occur when you use the Bitmap.FromFile method and one of the following conditions is true:
- The image file is corrupted.
- The image file is incomplete.
Note You may experience this problem if your application is trying to use the Bitmap.FromFile method on a file stream that is not finished writing to a file. * The image file does not have a valid image format or GDI+ does not support the pixel format of the file. * The program does not have permissions to access the image file. * The BackgroundImage property is set directly from the Bitmap.FromFile method.
(Bitmap descends from Image)
Of course, it's also possible to get this exception when you try to load an image which is too big. So you need to consider that.
来源:https://stackoverflow.com/questions/2610416/is-there-a-reason-image-fromfile-throws-an-outofmemoryexception-for-an-invalid-i