java - 如何从 fileBytes 确定扩展名

标签 java download http-headers file-extension

我的应用程序允许用户下载文件。创建 header 时,我使用 Tika 设置扩展名,如下所示。 这对于 pdf 文件效果很好。 DOC 和 EXCEL 文件失败。

private HttpHeaders getHeaderData(byte[] fileBytes) throws IOException, MimeTypeException {
        final HttpHeaders headers = new HttpHeaders();

        TikaInputStream tikaStream = TikaInputStream.get(fileBytes);
        Tika tika = new Tika();
        String mimeType = tika.detect(tikaStream);
        headers.setContentType(MediaType.valueOf(mimeType));

        MimeTypes defaultMimeTypes = MimeTypes.getDefaultMimeTypes();
        String extension = defaultMimeTypes.forName(mimeType).getExtension();
        headers.add("file-ext", extension);

        return headers;
    }

我发现 pdf 文件的 mimeType 解析为 "application/pdf",但 excel 和 word 文件的 mimeType 解析为 "application/x-tika-ooxml"这就是问题所在。 如果我有一个以字节为单位的文件,如何获取 word(.docx) 和 excel(xlx、xlsx)格式。

为什么这对 pdf 有效?

最佳答案

摘要

简短的回答是:您必须使用 Tika 的检测器及其 MediaType 类 - 而不是 MimeTypes

稍微长一点的答案是:即使这样也无法解决问题,因为较旧的 MS-Office 文件的结构不同。对于那些您还必须解析文件并检查其元数据。

术语“媒体类型”已取代术语“MIME 类型” - 请参阅 here :

[RFC2046] specifies that Media Types (formerly known as MIME types) and Media Subtypes will be assigned and listed by the IANA.

Office 97-2003

当 Tika 使用其检测器检查 Excel 和 Word 97-2003 文件时,它将返回 application/x-tika-msoffice 媒体类型。我假设(可能是错误的)这是它处理文件类型组的方式,其中检测器无法根据其分析确定 MS-Office 97-2003 文件的特定风格。这与您问题中的 application/x-tika-ooxml 类似。

预期结果

基于 IANA 列表 here ,以及 Mozilla 列表 here ,这些是我们期望为以下文件类型获得的媒体类型:

  • .pdf::应用程序/pdf
  • .xls::application/vnd.ms-excel
  • .doc::application/msword
  • .xlsx::application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
  • .docx::application/vnd.openxmlformats-officedocument.wordprocessingml.document

计划

下面显示的程序使用以下 Maven 依赖项:

    <dependencies>
        <dependency>
            <groupId>org.apache.tika</groupId>
            <artifactId>tika-core</artifactId>
            <version>1.23</version>
        </dependency>
        <dependency>
            <groupId>org.apache.tika</groupId>
            <artifactId>tika-parsers</artifactId>
            <version>1.23</version>
        </dependency>
        <dependency>
            <groupId>javax.ws.rs</groupId>
            <artifactId>javax.ws.rs-api</artifactId>
            <version>2.1.1</version>
        </dependency>
    </dependencies>

该程序(仅用于此演示 - 尚未准备好生产)如下所示。具体来说,请查看 tikaDetect()tikaParse() 方法。

import java.io.IOException;
import java.io.File;
import java.io.FileInputStream;
import java.io.BufferedInputStream;
import java.util.Set;
import java.util.HashSet;
import org.apache.tika.mime.MediaType;
import org.apache.tika.mime.MimeTypeException;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.detect.Detector;
import org.apache.tika.detect.DefaultDetector;
import org.apache.tika.exception.TikaException;
import org.apache.tika.parser.Parser;
import org.apache.tika.parser.AutoDetectParser;
import org.apache.tika.sax.BodyContentHandler;
import org.apache.tika.parser.ParseContext;
import org.xml.sax.SAXException;
import org.xml.sax.ContentHandler;

public class Main {

    private final Set<File> msOfficeFiles = new HashSet();

    public static void main(String[] args) throws IOException, MimeTypeException,
            SAXException, TikaException {
        Main main = new Main();
        main.doFileDetection();
    }

    private void doFileDetection() throws IOException, MimeTypeException, SAXException, TikaException {
        File file1 = new File("C:/tmp/foo.pdf");
        File file2 = new File("C:/tmp/baz.xlsx");
        File file3 = new File("C:/tmp/bat.docx");
        // Excel 97-2003 format:
        File file4 = new File("C:/tmp/bar.xls");
        // Word 97-2003 format:
        File file5 = new File("C:/tmp/daz.doc");
        Set<File> files = new HashSet();
        files.add(file1);
        files.add(file2);
        files.add(file3);
        files.add(file4);
        files.add(file5);

        for (File file : files) {
            try (BufferedInputStream bis = new BufferedInputStream(
                    new FileInputStream(file))) {
                tikaDetect(file, bis);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        for (File file : msOfficeFiles) {
            tikaParse(file);
        }
    }

    private void tikaDetect(File file, BufferedInputStream bis)
            throws IOException, SAXException, TikaException {
        Detector detector = new DefaultDetector();
        Metadata metadata = new Metadata();
        MediaType mediaType = detector.detect(bis, metadata);
        if (mediaType.toString().equals("application/x-tika-msoffice")) {
            msOfficeFiles.add(file);
        } else {
            System.out.println("Media Type for " + file.getName()
                    + " is: " + mediaType.toString());
        }
    }

    private void tikaParse(File file) throws SAXException, TikaException {
        Parser parser = new AutoDetectParser();
        ContentHandler handler = new BodyContentHandler();
        Metadata metadata = new Metadata();
        ParseContext context = new ParseContext();
        try (BufferedInputStream bis = new BufferedInputStream(
                new FileInputStream(file))) {
            parser.parse(bis, handler, metadata, context);
            tikaDetect(file, bis);
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("Media Type for " + file.getName()
                + " is: " + metadata.get("Content-Type"));
    }
}

实际结果

该程序会生成一些警告和信息消息。如果我们在本练习中忽略这些,我们会得到以下打印语句:

Media Type for bat.docx is: application/vnd.openxmlformats-officedocument.wordprocessingml.document
Media Type for baz.xlsx is: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
Media Type for foo.pdf is: application/pdf
Media Type for bar.xls is: application/vnd.ms-excel
Media Type for daz.doc is: application/msword

这些与预期的官方媒体 (MIME) 类型匹配。

关于java - 如何从 fileBytes 确定扩展名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60535930/

相关文章:

java - 在Android上解密 "SunJCE"AES加密数据

download - 如何从 Karate 中的 api 端点获取下载的 xlsx 文件?

javascript - Tomcat 5.5 的跨源资源共享

java - 如何从HTTP CORS获取文件信息?

java - 如何获取 Spring REST 文件下载以返回 404?

java - 每个帐户的 Hibernate/JPA 增量列

java - 运行 Gradle 导致 - 错误 : Could not find or load main class security. provider.1=org.bouncycaSTLe.jce.provider.BouncyCaSTLeProvider

svn - 下载 SVN 存储库/文件夹的在线服务?

c# - 如何使用 c# 在 asp.net 中恢复能够下载的文件 -> 最佳方式(也适用于大文件)

jquery - Access-Control-Allow-Origin header 不起作用 - 我做错了什么?