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

关于如何判断一个文件的类型,在如何判断一个文件的类型_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);
    }

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java中,可以通过以下方法来判断上传文件类型: 1. 通过文件名后缀名判断 可以通过文件名中的后缀名来判断文件类型,例如: ```java String fileName = "example.jpg"; if (fileName.endsWith(".jpg") || fileName.endsWith(".jpeg")) { // 文件类型为jpg或jpeg } else if (fileName.endsWith(".png")) { // 文件类型为png } else { // 其他文件类型 } ``` 但需要注意的是,文件名后缀可以被篡改,因此此方法不是十分可靠。 2. 通过文件的MIME类型判断 可以通过文件的MIME类型判断文件类型,例如: ```java import javax.activation.MimetypesFileTypeMap; MimetypesFileTypeMap mimeTypesMap = new MimetypesFileTypeMap(); String mimeType = mimeTypesMap.getContentType(filePath); if (mimeType.startsWith("image/")) { // 文件类型为图片 } else if (mimeType.startsWith("video/")) { // 文件类型为视频 } else if (mimeType.startsWith("text/")) { // 文件类型为文本文件 } else { // 其他文件类型 } ``` 需要注意的是,MIME类型也可以被篡改。 3. 通过文件内容判断 可以通过读取文件的内容判断文件类型,例如: ```java import java.io.*; public static String getFileType(String filePath) throws IOException { InputStream inputStream = new FileInputStream(filePath); byte[] bytes = new byte[4]; inputStream.read(bytes); inputStream.close(); String type = ""; String fileHead = bytesToHexString(bytes); if (fileHead == null || fileHead.length() == 0) { return null; } fileHead = fileHead.toUpperCase(); FileType[] fileTypes = FileType.values(); for (FileType fileType : fileTypes) { if (fileHead.startsWith(fileType.getValue())) { type = fileType.name(); break; } } return type; } public static String bytesToHexString(byte[] bytes) { StringBuilder stringBuilder = new StringBuilder(); if (bytes == null || bytes.length <= 0) { return null; } for (int i = 0; i < bytes.length; i++) { int v = bytes[i] & 0xFF; String hv = Integer.toHexString(v); if (hv.length() < 2) { stringBuilder.append(0); } stringBuilder.append(hv); } return stringBuilder.toString(); } enum FileType { JPEG("FFD8FF"), // JPEG (jpg) PNG("89504E47"), // PNG (png) GIF("47494638"), // GIF (gif) TIFF("49492A00"), // TIFF (tif) BMP("424D"), // Windows Bitmap (bmp) DWG("41433130"), // CAD (dwg) PSD("38425053"), // Adobe Photoshop (psd) RTF("7B5C727466"), // Rich Text Format (rtf) XML("3C3F786D6C"), // XML (xml) HTML("68746D6C3E"), // HTML (html) PDF("255044462D312E"), // Adobe PDF (pdf) ZIP("504B0304"), // ZIP Archive (zip) RAR("52617221"), // RAR Archive (rar) WAV("57415645"), // Wave (wav) AVI("41564920"), // AVI (avi) MP4("00000020667479706D70"), // MPEG-4 (mp4) MPG("000001BA"), // MPEG (mpg) WMV("3026B2758E66CF11"), // Windows Media Video (wmv) MID("4D546864"); // MIDI (mid) private String value = ""; private FileType(String value) { this.value = value; } public String getValue() { return value; } } ``` 此方法可以通过读取文件的前几个字节来判断文件类型,比较可靠,但需要注意的是,不同类型的文件前几个字节可能是相同的,因此有一定的误判率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值