java - 如何准确地确定文件中的 mime 数据?

标签 java mime-types file-type

我正在向程序添加一些功能,以便我可以通过读取 MIME 数据准确地确定文件类型。我已经尝试了几种方法:

方法一:

javax.activation.FileDataSource

FileDataSource ds = new FileDataSource("~\\Downloads\\777135_new.xls");  
String contentType = ds.getContentType();  
System.out.println("The MIME type of the file is: " + contentType);

//output = The MIME type of the file is: application/octet-stream

方法二:

import net.sf.jmimemagic.*;

try
{
    RandomAccessFile f = new RandomAccessFile("~\\Downloads\\777135_new.xls", "r");
    byte[] fileBytes = new byte[(int)f.length()];
    f.read(fileBytes);
    MagicMatch match = Magic.getMagicMatch(fileBytes);
    System.out.println("The Mime type is: " + match.getMimeType());
}
catch(Exception e)
{
    System.out.println(e);
}

//output = The Mime type is: application/msword

方法三:

import eu.medsea.mimeutil.*;

MimeUtil.registerMimeDetector("eu.medsea.mimeutil.detector.MagicMimeMimeDetector");
File f = new File ("~\\Downloads\\777135_new.xls");
Collection<?> mimeTypes = MimeUtil.getMimeTypes(f);
String mimeType = MimeUtil.getFirstMimeType(mimeTypes.toString()).toString();
String subMimeType = MimeUtil.getSubType(mimeTypes.toString());
System.out.println("The Mime type is: " + mimeTypes + ", " + mimeType + ", " + subMimeType);

//output = The Mime type is: application/msword, application/msword, msword

我在 http://www.rgagnon.com/javadetails/java-0487.html 找到了这三种方法.但是我的问题是我正在测试这些方法的文件是我创建的,所以我知道它是一个 Excel 文件,但所有三种方法仍然错误地将类型拾取为 msword 除了我认为是因为第一种方法该方法使用的内置 FileTypeMap 中的文件类型数量有限。

我环顾四周,有人说这是因为在文件中检测到偏移量的方式导致内容类型被错误地拾取,如 wiki 中所指出的那样关于在 PHP 中检测文件类型。不幸的是,wiki 然后继续使用扩展名来确定文件类型,这不是我想要做的,因为它不可靠。

谁能给我指明正确的方向,让我找到一种可以在 Java 中正确检测文件类型的方法?

干杯, 阿列克谢蓝。

编辑:正如@IronMensan 在下面的评论中所说,看起来没有具体的解决方案。我确实发现这真的很有趣 research paper它以几种方式应用机器学习来帮助解决问题,但似乎没有完整的证明答案。我认为我最好的选择是尝试将文件传递给 excel 文件阅读器并捕获任何格式不正确的异常。

最佳答案

到目前为止,我发现确定文件 MIME 类型的最准确工具是 Apache Tika .这是对我目前使用的(Tika 1.0 版)的轻微修改

import org.apache.tika.detect.DefaultDetector;
import org.apache.tika.detect.Detector;
import org.apache.tika.io.TikaInputStream;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.mime.MimeTypes;

private static final Detector DETECTOR = new DefaultDetector(
        MimeTypes.getDefaultMimeTypes());

public static String detectMimeType(final File file) throws IOException {
    TikaInputStream tikaIS = null;
    try {
        tikaIS = TikaInputStream.get(file);

        /*
         * You might not want to provide the file's name. If you provide an Excel
         * document with a .xls extension, it will get it correct right away; but
         * if you provide an Excel document with .doc extension, it will guess it
         * to be a Word document
         */
        final Metadata metadata = new Metadata();
        // metadata.set(Metadata.RESOURCE_NAME_KEY, file.getName());

        return DETECTOR.detect(tikaIS, metadata).toString();
    } finally {
        if (tikaIS != null) {
            tikaIS.close();
        }
    }
}

由于 Tika 会使用魔数(Magic Number),但在不确定时也会查看文件的内容,这个过程可能会有点耗时(我的 PC 检查 15 个文件需要 3.268 秒)。

还有,不要犯我一开始犯的同样的错误。如果您获得 tika-core JAR,您还应该获得 tika-parsers JAR。如果您没有得到 tika-parsers,您将不会得到任何异常,您将无法准确地得到 MIME 类型,因此包含它真的很重要。

另一种方法是获取 tika-app JAR,其中包含 tika-coretika-parsers 和所有依赖项 (它们很多:poi、poi-ooxml、xmlbeans、commons-compress,仅举几例)。

关于java - 如何准确地确定文件中的 mime 数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8488491/

相关文章:

java - 泛型类型的迭代器设计模式

java - 无法从 Spring Boot 应用程序 Autowiring yml 配置类

html - Chrome 报告 html5 缓存 list mime 类型不正确

有效 JSON 上的 jQuery getJSON 语法错误

android - 如何检查是否可以从某些 Activity 中处理 Intent ?

RMI 中的 java.lang.ClassNotFoundException,没有禁用安全管理器 RMI 类加载器

java - 将java控制台输出复制到Excel中,行而不是列

php - Mime 类型 PDF php 上传

sublimetext - Sublime无法识别扩展

python - 使用 argparse 传递给 python 脚本的文件类型检查参数