【问题标题】:Test if a file is an image file测试文件是否为图像文件
【发布时间】:2012-03-27 10:41:11
【问题描述】:

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

【问题讨论】:

标签: java image file io


【解决方案1】:

这是我的代码,基于使用 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);
    }
}

【讨论】:

    【解决方案2】:

    其他答案建议将完整图像加载到内存中(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 answerImageIO.read

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

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

    【讨论】:

      【解决方案3】:

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

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

      • 如果后缀不标准或错误,依赖文件后缀的方法将被欺骗。

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

      • 依赖于查看文件签名的方法可能会被恰好具有相同签名字节的二进制文件欺骗。

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

      【讨论】:

        【解决方案4】:

        你可以试试这样的:

        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】:
          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?

          【讨论】:

          • 如果文件是图像文件(在带有 Java 8 的 Ubuntu 系统上),这是我能找到的唯一方法。
          【解决方案6】:

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

          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 帖子stackoverflow.com/questions/4855627/…
          • 如果是来自URL呢?在将 URL 保存到文件之前?我得到“应用程序/八位字节流”而不是图像。有什么想法吗?
          • @dermoritz,我也是。“new MimetypesFileTypeMap().getContentType(path)”返回“application/octet-stream”,但“URLConnection.guessContentTypeFromName(path)”返回正确的 mime 类型。
          • 这仅根据文件的扩展名进行检查。使用此方法无法检测到无效图像(没有图像内容和正确文件头的其他二进制文件)。
          • 这是测试文件是否为图像的不好方法。更好的解决方案是: Files.probeContentType(path);
          【解决方案7】:

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

          【讨论】:

          • 在Linux上,似乎只看我机器上的扩展。将 .jpeg 文件更改为 .txt 并返回“text/plain”。我喜欢克里斯蒂安在下面的回答。
          【解决方案8】:

          你可以试试这样的:

             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
             }
          

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

          【讨论】:

          • 对不起,当我写答案时,你的答案不在那里......也许我写的时间太长了。但你是对的,它完全一样:)
          • 嗯嗯,没问题。我想这里的每个人都会遇到这种情况。 :)
          • @ismaelga - 事实上,这种情况经常发生,大多数人甚至都懒得评论它。
          • @StephenC - 我是个坏人,我知道。我刚刚评论是因为大约有 30 分钟的间隔,但我知道这仍然是正常的事情。 :) 我不是在讽刺
          猜你喜欢
          • 2015-07-15
          • 2011-02-03
          • 1970-01-01
          • 2021-06-26
          • 1970-01-01
          • 2011-01-12
          • 2010-10-14
          • 2012-07-06
          • 1970-01-01
          相关资源
          最近更新 更多