我不想依赖于文件扩展名。我不关心它是什么类型的图像(.jpg,.png等),我只想知道该文件是否是一个图像。如果可能的话,我宁愿不使用任何非.NET的DLL。
我所知道的最佳方法如下:
bool isImageFile;
try
{
Image.FromFile(imageFile).Dispose();
isImageFile = true;
}
catch (OutOfMemoryException)
{
isImageFile = false;
}
如下所述:如果文件不是有效的图像格式,http://msdn.microsoft.com/en-us/library/stf701f5.aspx,Image.FromFile()
将抛出OutOfMemoryException
。使用上面的方法可以得到我想要的结果,但由于以下原因,我不希望使用它:
- 我认为,出于性能原因,使用try-catch执行正常程序是一种不好的做法。
Image.FromFile()
将整个图像文件(如果它是图像文件)加载到内存中,我认为这是浪费,因为我只需要文件类型,而不需要在代码的这一点上做任何进一步的图像操作。- 我不喜欢捕获
OutOfMemoryException
s,因为如果真实的的出现内存不足的问题,而我的程序吞下它并继续运行,那该怎么办?
**是否有更好的方法来实现这一点?**或者,我上面列出的任何/所有顾虑是否都是没有根据的?
编辑:自从在这里收到答案后,我现在知道三种解决方案: - 通过
Image.FromFile()
和try-catch将整个图像加载到内存中。 - 优点 *:对图像文件内容进行更深入的检查;涵盖许多图像类型。
- 缺点 *:最慢;来自try-catch和将完整图像文件加载到内存中的开销;捕获“真实的的”OutOfMemoryException的潜在危险。
- 检查图像文件的标头字节。
- 优点 *:速度快,内存使用率低。
- 缺点 *:可能易碎;需要为每种文件类型编程。
- 检查文件扩展名。
- 优点 *:最快;最简单。
- 缺点 *:并非在所有情况下都有效;最容易出错。
(我没有看到一个明确的“赢家”,因为我可以想象每一种方法都适用的情况。对于我的应用程序来说,文件类型检查很少发生,因此方法1的性能问题不是问题。)
7条答案
按热度按时间p8ekf7hl1#
如果您只支持少数几种流行的图像格式,那么您可以简单地读取文件的前几个字节,根据Magic Number来确定类型
所提供链接中的示例:
w8f9ii692#
1.只有当你不断抛出异常时,你才会注意到异常对性能的影响,所以除非你的程序期望看到很多无效图像(每秒数百个),否则你不应该注意异常处理的开销。
1.这确实是判断映像是完整映像还是损坏映像的唯一方法。您可以按照其他人的建议检查标头,但这仅检查开头几个字节是否正确,其他任何内容都可能是垃圾。这是否足够好取决于您的应用程序的要求。仅阅读标头可能对您的用例足够好。
1.是的,这是BCL团队的一个相当糟糕的设计。如果你加载很多大的图像,你很可能会在大对象堆中遇到一个真实的的OOM情况。据我所知,没有办法区分这两个例外。
7ivaypg93#
我可以理解您的顾虑,但是如果您查看Image.FromFile方法的源代码,它只是GDI+调用的 Package 器,因此遗憾的是您不能什么也不做,因为正如我所看到的,异常的bizzare选择(OutOfMemoryException)是在GDI+中完成的
所以看起来你被当前的代码卡住了,或者检查文件头,但是这并不能保证文件真的是一个有效的图像。
也许你应该首先考虑一下你真的需要isImageFile方法吗?在扩展名上检测图像文件,这样会快得多,如果从文件加载失败,它会引发一个异常,这样你就可以在真正需要加载图像时处理它。
ybzsozfc4#
采用检查文件头的方法,我编写了以下实现:
我把它和方法沿着放到一个实用程序/helper类中:
GetFileImageTypeFromFullLoad()
和GetFileImageTypeFromExtension()
。前者使用我上面提到的Image.FromFile
方法,后者只是检查文件扩展名。我计划根据情况的需要使用这三种方法。jvidinwx5#
首先使用System.IO.Path.GetExtension()方法来检查扩展是否是图像类型。然后如果你想完成,你可以检查文件中的头。
kse8i1jr6#
下面是一个使用Gdi+中签名的例子:
5hcedyr07#
要检查文件是否为正确的图像文件,可以使用ImageSharp加载它:
如果它抛出异常,它不是一个正确的图像文件。请注意,ImageSharp只支持某些子集的图像格式。