测试文件是否为图像文件

时间:2012-03-10 01:48:27

标签: java image file io

我正在使用某个文件IO并想知道是否有方法来检查文件是否为图像?

8 个答案:

答案 0 :(得分:46)

这对我来说效果很好。希望我能帮忙

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");
    }
}

答案 1 :(得分:21)

if( ImageIO.read(*here your input stream*) == null)
    *IS NOT IMAGE*    

还有答案:How to check a uploaded file whether it is a image or other file?

答案 2 :(得分:12)

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

答案 3 :(得分:8)

您可以尝试这样的事情:

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");
}

答案 4 :(得分: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
   }

这应该有用,虽然它似乎不是最优雅的版本。

答案 5 :(得分:3)

有多种方法可以做到这一点;查看其他答案以及相关问题的链接。 (Java 7方法对我来说似乎最吸引人,因为默认情况下它使用特定于平台的约定,您可以提供自己的方案来确定文件类型。)

但是,我只想指出,没有任何机制是绝对可靠的:

  • 如果后缀为非标准或错误,则会欺骗依赖文件后缀的方法。

  • 如果文件的内容类型属性不正确或根本没有,则会欺骗依赖文件属性的方法(例如在文件系统中)。

  • 依赖于查看文件签名的方法可能被二进制文件欺骗,而这些文件碰巧具有相同的签名字节。

  • 如果您运气不好,即使只是尝试将文件作为图像读取也会被欺骗......取决于您尝试的图像格式。

答案 6 :(得分:1)

其他答案建议将完整图像加载到内存(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在当前实现中仅检查文件扩展名。

TLDR

  • 如果您打算对读取的图像进行某些操作(例如调整大小/裁剪/旋转图像),请使用Krystian's answer中的ImageIO.read

  • 如果您只想检查(也许存储)真实的Content-Type,请使用Tika(此答案)。

  • 如果您在受信任的环境中工作,并且100%确定文件扩展名正确,请使用prunge's Answer中的Files.probeContentType

答案 7 :(得分:0)

这是我基于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);
    }
}