如何确定文件是否是.NET中的图像文件?

Dar*_*ryl 18 .net file-format file-type image

我不想依赖文件扩展名.我不知道它是什么类型的图像(.jpg,.png等),我只是想知道文件是否是图像.如果可能的话,我宁愿不使用任何非.NET dll.

我知道如何做到这一点的最好方法如下:

bool isImageFile;
try
{
    Image.FromFile(imageFile).Dispose();
    isImageFile = true;
}
catch (OutOfMemoryException)
{
    isImageFile = false;
}
Run Code Online (Sandbox Code Playgroud)

如上所述:http://msdn.microsoft.com/en-us/library/stf701f5.aspx,如果文件不是有效的图像格式,则Image.FromFile()抛出一个OutOfMemoryException.使用上面给出了我想要的结果,但是由于以下原因我不想使用它:

  • 我认为,出于性能原因,使用try-catches进行正常程序执行是一种不好的做法.
  • Image.FromFile()将整个图像文件(如果是图像文件)加载到内存中.这是浪费我假设因为我只需要文件类型,并且在我的代码中此时不需要进行任何进一步的图像处理.
  • 我不喜欢捕捉OutOfMemoryExceptions,因为如果有一个真正的内存不足问题,我的程序吞下它并继续前进?

有没有更好的方法来做到这一点?或者,我上面列出的任何/所有问题都是无根据的?

编辑:自从收到答案后,这些是我现在知道的三个解决方案:

  1. 通过Image.FromFile()try-catch 将整个图像加载到内存中.
    • 优点:对图像文件内容进行更深入的检查; 涵盖了许多图像类型.
    • 缺点:最慢; 从try-catch开始并将完整的映像文件加载到内存中; 捕获'真实'OutOfMemoryException的潜在危险.
  2. 检查图像文件的标题字节.
    • 优点:快速,低内存使用率.
    • 缺点:可能脆弱; 需要为每种文件类型编程.
  3. 检查文件扩展名.
    • 优点:最快; 最简单的.
    • 缺点:不适用于所有情况; 最容易出错.

(我没有看到明确的"赢家",因为我可以想象每个人都适合的情况.对于我的应用程序的目的,文件类型检查不经常发生,方法1的性能问题不是问题.)

taw*_*man 11

如果您只支持少数流行的图像格式,那么您只需读取文件的前几个字节即可根据幻数确定类型

提供的链接示例:

  • GIF图像文件的ASCII代码为"GIF89a"(47 49 46 38 39 61)或"GIF87a"(47 49 46 38 37 61)
  • JPEG图像文件以FF D8开头,以FF D9结束.JPEG/JFIF文件包含"JFIF"(4A 46 49 46)的ASCII代码,作为空终止字符串.
  • PNG图像文件以8字节签名开头,该签名将文件标识为PNG文件,并允许检测常见的文件传输问题:\ 211 PNG\r \n\032 \n(89 50 4E 47 0D 0A 1A 0A).


Jar*_*ver 8

  1. 如果你不断抛出它们,你只会注意到异常的性能损失.因此,除非您的程序期望看到许多无效图像(每秒数百个),否则您不应该注意到异常处理的开销.
  2. 这实际上是判断图像是完整图像还是损坏的唯一方法.你可以像其他人推荐的那样检查标题,但是只检查开头的几个字节是否正确,其他任何东西都可能是垃圾.这是否足够好取决于您的应用程序的要求.只是阅读标题可能足以满足您的使用案例.
  3. 是的,BCL团队的设计相当糟糕.如果要加载许多大图像,那么很可能会在大对象堆中遇到真正的OOM情况.据我所知,没有办法区分这两个例外.