Java如何判断一个上传文件的内容类型

2022-07-27 13:09:58

关于如何判断一个文件的类型,在如何判断一个文件的类型_jimmyleeee的博客-CSDN博客已经介绍了,但是在实际运用于真正的文件上传时,还是有些注意事项需要注意的。

在进入主题之前,首先需要简单介绍一下MultipartFile这个类,通过getOriginalFilename()获取文件的名字,但是这个名字只是上传文件的名字,通过这个名字是无法访问到这个文件的。以下是测试时的debug信息:

可以看到 MultipartFile类中,有filename,有filelocation,甚至还有临时文件的绝对路劲和名字,但是,却没有接口可以获取这些信息。也就是说,通过类MultipartFile只能获得文件名和文件流。

再说,使用Files.probeContentType检测上传的MultipartFile时,为什么可以正常工作。在Files.probeContentType中设置一个断点,可以发现进入函数之后,会直接调转到1624行,调用

FileTypeDetectors.defaultFileTypeDetector的probeContentType

 通过进一步定义跟踪,默认的defaultFileTypeDetector是RegistryFileTypeDetector,根据基类AbstractFileTypeDetector中probeContentType的实现如下:

public final String probeContentType(Path var1) throws IOException {
        if (var1 == null) {
            throw new NullPointerException("'file' is null");
        } else {
            String var2 = this.implProbeContentType(var1);
            if (var2 == null) {
                Path var3 = var1.getFileName();
                if (var3 != null) {
                    FileNameMap var4 = URLConnection.getFileNameMap();
                    var2 = var4.getContentTypeFor(var3.toString());
                }
            }

            return var2 == null ? null : parse(var2);
        }
    }

其中,主要是implProbeContentType中实现对内容类型的分析。回到RegistryFileTypeDetector的implProbeContentType函数:

public String implProbeContentType(Path var1) throws IOException {
        if (!(var1 instanceof Path)) {
            return null;
        } else {
            Path var2 = var1.getFileName();
            if (var2 == null) {
                return null;
            } else {
                String var3 = var2.toString();
                int var4 = var3.lastIndexOf(46);
                if (var4 >= 0 && var4 != var3.length() - 1) {
                    String var5 = var3.substring(var4);
                    NativeBuffer var6 = null;
                    NativeBuffer var7 = null;

                    Object var9;
                    try {
                        var6 = WindowsNativeDispatcher.asNativeBuffer(var5);
                        var7 = WindowsNativeDispatcher.asNativeBuffer("Content Type");
                        String var8 = queryStringValue(var6.address(), var7.address());
                        return var8;
                    } catch (WindowsException var13) {
                        var13.rethrowAsIOException(var1.toString());
                        var9 = null;
                    } finally {
                        var7.release();
                        var6.release();
                    }

                    return (String)var9;
                } else {
                    return null;
                }
            }
        }
    }

在这里可以看到文件名var2之后,就在文件名上进行进一步分析和判断,没有读取文件。所以,默认的detector,即使没有实际的文件,只要根据文件名,就可以判断一个文件的内容类型,虽然,有时不准确,例如,将一个png文件改成txt的扩展名,分析出来的结果就是:text/plain。根据类的实现,也可以通过加载自己实现的类型检测类,然后,再调用Files.probeContentType就可以使用自己的类型探测类了。

而使用Tika调用String detect(File file)接口时,如果文件不存在,就会跑出IO异常:

        Tika defaultTika = new Tika();
        
        String fileType;
        try
        {
            final File file = new File(fileName);
            fileType = defaultTika.detect(file);
        }
        catch (IOException ioEx)
        {
            fileType = "Unknown";
        }

因此,在处理上传的文件时,使用MultipartFile.getOriginalFilename获取的文件名生成一个File对象来获取文件内容类型,会出IOException 异常。而且将file转成File对象时,还可能会产生临时文件。

不过,还好的是Tika还提供了一个针对stream流的接口:String detect(String name)

        Tika defaultTika = new Tika();
        MultipartFile multipartFile = multipartHttpServletRequest.getFile(key);

        String fileType;
        
        try
        {
            InputStream stream = multipartFile.getInputStream();
            fileType = defaultTika.detect(stream);
        }
        catch (IOException ioEx)
        {
            fileType = "Unknown";
        }

Tika还提供了Parser,可以通过Parser对InputStream分析得到文件的内容类型与Tika.detect(InputStream)的结果是一样的,示例代码如下:

public static String getMimeTypeByParser(InputStream stream) {
        AutoDetectParser parser = new AutoDetectParser();
        Metadata metadata = new Metadata();
        BodyContentHandler handler = new BodyContentHandler();
        try {
            parser.parse(stream, handler, metadata);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (SAXException e) {
            e.printStackTrace();
        } catch (TikaException e) {
            e.printStackTrace();
        }

        return metadata.get(HttpHeaders.CONTENT_TYPE);
    }
  • 作者:jimmyleeee
  • 原文链接:https://blog.csdn.net/jimmyleeee/article/details/124255347
    更新时间:2022-07-27 13:09:58