如何检查上传的文件是图像还是其他文件?

27 java bufferedimage servlets file-upload image

在我的Web应用程序中,我有一个图像上传模块.我想检查上传的文件,无论是图像文件还是任何其他文件.我在服务器端使用Java.

图像BufferedImage在java中读取,然后我将其写入磁盘ImageIO.write()

我该如何检查BufferedImage,无论是真的是图像还是其他什么?

任何建议或链接将不胜感激.

Bal*_*usC 92

我假设你在servlet上下文中运行它.如果只根据文件扩展名检查内容类型是否可以负担得起,那么使用ServletContext#getMimeType()获取mime类型(内容类型).只需检查它是否以image/.

String fileName = uploadedFile.getFileName();
String mimeType = getServletContext().getMimeType(fileName);
if (mimeType.startsWith("image/")) {
    // It's an image.
}
Run Code Online (Sandbox Code Playgroud)

默认的mime类型在相关web.xml的servletcontainer中定义.例如Tomcat,它位于/conf/web.xml.您可以在/WEB-INF/web.xmlwebapp中扩展/覆盖它,如下所示:

<mime-mapping>
    <extension>svg</extension>
    <mime-type>image/svg+xml</mime-type>
</mime-mapping>
Run Code Online (Sandbox Code Playgroud)

但这并不能阻止那些通过更改文件扩展名来欺骗您的用户.如果您还想覆盖它,那么您还可以根据实际文件内容确定mime类型.如果只检查BMP,GIF,JPG或PNG类型(但不是TIF,PSD,SVG等)是可以负担得起的,那么您可以直接将其提供给它ImageIO#read()并检查它是否不会引发异常.

try (InputStream input = uploadedFile.getInputStream()) {
    try {
        ImageIO.read(input).toString();
        // It's an image (only BMP, GIF, JPG and PNG are recognized).
    } catch (Exception e) {
        // It's not an image.
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,如果您还想覆盖更多图像类型,请考虑使用第三方库,通过嗅探文件头来完成所有工作.例如JMimeMagicApache Tika,它们同时支持BMP,GIF,JPG,PNG,TIF和PSD(但不支持SVG).Apache Batik支持SVG.下面的例子使用JMimeMagic:

try (InputStream input = uploadedFile.getInputStream()) {
    String mimeType = Magic.getMagicMatch(input, false).getMimeType();
    if (mimeType.startsWith("image/")) {
        // It's an image.
    } else {
        // It's not an image.
    }
}
Run Code Online (Sandbox Code Playgroud)

如果有必要,您可以使用组合并超过其他组合.

也就是说,您不一定需要ImageIO#write()将上传的图像保存到磁盘.只是写所获得的InputStream直接向Path或任何OutputStream类似FileOutputStream通常的Java IO方式是绰绰有余(见推荐的方式保存在一个servlet的应用程序上传的文件):

try (InputStream input = uploadedFile.getInputStream()) {
    Files.copy(input, new File(uploadFolder, fileName).toPath());
}
Run Code Online (Sandbox Code Playgroud)

除非您想收集一些图像信息,如尺寸和/或想要操纵它(当然,裁剪/调整大小/旋转/转换/等).

  • ImageIO.read(输入); 如果文件不是图像,则不会抛出任何异常,而只返回null. (3认同)

小智 7

在我的例子中,我使用了org.apache.commons.imaging.Imaging。下面是一段示例代码,用于检查图像是否为 jpeg 图像。如果上传的文件不是图像,它会抛出 ImageReadException。

    try {
        //image is InputStream
        byte[] byteArray = IOUtils.toByteArray(image);
        ImageFormat mimeType = Imaging.guessFormat(byteArray);
        if (mimeType == ImageFormats.JPEG) {
            return;
        } else {
            // handle image of different format. Ex: PNG
        }
    } catch (ImageReadException e) {
        //not an image
    }
Run Code Online (Sandbox Code Playgroud)

  • 仍然 - 截至 2017 年 6 月,该库没有稳定版本,只有快照。在生产中使用可能有风险 (2认同)

gcs*_*ang 5

这是内置于 JDK 中的,只需要一个支持以下功能的流:

byte[] data = ;
InputStream is = new BufferedInputStream(new ByteArrayInputStream(data));
String mimeType = URLConnection.guessContentTypeFromStream(is);
//...close stream
Run Code Online (Sandbox Code Playgroud)

从 Java SE 6 开始https://docs.oracle.com/javase/6/docs/api/java/net/URLConnection.html