测试一个文件是否为图像文件

41

我正在使用一些文件IO,想知道是否有一种方法可以检查一个文件是否为图像?


1
请点击以下链接查看关于如何判断文件是否为图像的编程问题:https://dev59.com/vHRB5IYBdhLWcg3wSVcI(该问题是关于检查文件头部,与具体编程语言无关),或者https://dev59.com/70vSa4cB1Zd3GeqPg70K,或者https://dev59.com/AWDVa4cB1Zd3GeqPcVQo。 - wkl
8个回答

62

这对我来说非常有效。希望我能帮到你。

import javax.activation.MimetypesFileTypeMap;
import java.io.File;
class Untitled {
    public static void main(String[] args) {
        String filepath = "/the/file/path/image.jpg";
        File f = new File(filepath);
        String mimetype= new MimetypesFileTypeMap().getContentType(f);
        String type = mimetype.split("/")[0];
        if(type.equals("image"))
            System.out.println("It's an image");
        else 
            System.out.println("It's NOT an image");
    }
}

嗨@dermoritz,这似乎是您系统上的问题。请查看此SO帖子https://dev59.com/k1PTa4cB1Zd3GeqPneVW - Ismael
它检查文件内容还是只检查扩展名? - gstackoverflow
10
这只是基于文件扩展名进行检查,无法使用此方法检测非有效图像(其他二进制文件没有图像内容和正确的文件头)。 - Alex Fedulov
你是对的 @Alex Fedulov。如果这还不够,可以尝试prunge的答案。 - Ismael
7
这种方式不适合测试文件是否为图像,更好的解决方案是:Files.probeContentType(path); - Biagio Cannistraro
显示剩余3条评论

37

1
这是我在Ubuntu系统上使用Java 8找到的判断文件是否为图像文件的唯一方法。 - zafar142003

18
在Java 7中,有一个名为 java.nio.file.Files.probeContentType() 的方法。在Windows上,它使用文件扩展名和注册表来确定文件类型(不是探测文件内容)。然后,您可以检查MIME类型的第二部分,并检查其是否以<X>/image的形式出现。

3
在Linux上,它似乎只查看我的机器上的文件扩展名。将一个 .jpeg 文件更改为 .txt,它返回了 "text/plain"。我喜欢下面Krystian的答案。 - yngwietiger

13

你可以尝试类似这样的方法:

String pathname="abc\xyz.png"
File file=new File(pathname);


String mimetype = Files.probeContentType(file.toPath());
//mimetype should be something like "image/png"

if (mimetype != null && mimetype.split("/")[0].equals("image")) {
    System.out.println("it is an image");
}

5
其他答案建议将完整图像加载到内存中(ImageIO.read),或使用标准JDK方法(MimetypesFileTypeMapFiles.probeContentType)。

如果不需要读取图像,而只是想测试它是否为图像(并可能将其内容类型保存在Content-Type响应头中,以便将来读取此图像时设置),第一种方法效率不高。

传入的JDK方式通常只测试文件扩展名,不能真正给出您可以信任的结果。

对我有效的方法是使用Apache Tika库。

private final Tika tika = new Tika();

private MimeType detectImageContentType(InputStream inputStream, String fileExtension) {
    Assert.notNull(inputStream, "InputStream must not be null");

    String fileName = fileExtension != null ? "image." + fileExtension : "image";
    MimeType detectedContentType = MimeType.valueOf(tika.detect(inputStream, fileName));
    log.trace("Detected image content type: {}", detectedContentType);

    if (!validMimeTypes.contains(detectedContentType)) {
        throw new InvalidImageContentTypeException(detectedContentType);
    }

    return detectedContentType;
}

该类型检测基于给定文档流的内容和文档名称。仅从流中读取有限数量的字节。
我将fileExtension作为提示传递给Tika。不过,根据文档,它在某些情况下有助于更好地检测。
ImageIO.read相比,此方法的主要优点是Tika不会将整个文件读入内存,而只读取前几个字节。
与JDK的MimetypesFileTypeMapFiles.probeContentType相比,其主要优点是Tika确实读取了文件的前几个字节,而JDK在当前实现中仅检查文件扩展名。
简而言之:
- 如果您计划对读取的图像进行处理(如调整大小/裁剪/旋转),则使用Krystian's answer中的ImageIO.read。 - 如果您只想检查(并可能存储)真正的Content-Type,则使用Tika(本答案)。 - 如果您在可信环境中工作,并且您100%确定文件扩展名正确,则使用prunge's Answer中的Files.probeContentType

4
您可以尝试像这样的操作:
   import javax.activation.MimetypesFileTypeMap;

   File myFile;

   String mimeType = new MimetypesFileTypeMap().getContentType( myFile ));
   // mimeType should now be something like "image/png"

   if(mimeType.substring(0,5).equalsIgnoreCase("image")){
         // its an image
   }

这应该可以工作,尽管它似乎不是最优雅的版本。

1
抱歉,当我写我的答案时你的回复还没有出现……也许我花了太长时间来写它。但是你是对的,完全一样 :) - GameDroids
嘿嘿,没问题。我想这种情况在这里每个人都经常遇到。 :) - Ismael
1
@ismaelga - 的确,这种情况经常发生,大多数人甚至都不会费心去评论它。 - Stephen C
@StephenC - 我知道我是个坏人。我只是因为有大约30分钟的间隔才发表了评论,但我知道这仍然是正常的事情。 :) 我并不是在讽刺。 - Ismael

4
有多种方法可以实现这一点,请参见其他答案和相关问题的链接。(对我来说,Java 7方法似乎最具吸引力,因为它默认使用特定于平台的约定,并且您可以提供自己的文件类型确定方案。) 但是,我想指出没有一种机制是完全不失效的:
- 如果后缀非标准或错误,则依赖文件后缀的方法将被欺骗。 - 如果文件具有不正确的内容类型属性或根本没有属性,则依赖文件属性(例如在文件系统中)的方法将被欺骗。 - 依赖查看文件签名的方法可能会被那些恰好具有相同签名字节的二进制文件欺骗。 - 即使只是尝试将文件读取为图像,如果你不幸运的话,也会被欺骗...这取决于你尝试的图像格式。

2

这是基于使用tika的答案的代码。

private static final Tika TIKA = new Tika();
public boolean isImageMimeType(File src) {
    try (FileInputStream fis = new FileInputStream(src)) {
        String mime = TIKA.detect(fis, src.getName());
        return mime.contains("/") 
                && mime.split("/")[0].equalsIgnoreCase("image");
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接