Как точно определить данные MIME из файла? - PullRequest
14 голосов
/ 13 декабря 2011

Я добавляю некоторые функции в программу, чтобы я мог точно определить тип файлов, читая данные MIME.Я уже попробовал несколько методов:

Метод 1:

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

Метод 2:

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

Метод 3:

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.К сожалению, затем вики продолжает использовать расширение, чтобы определить тип файла, а это не то, что я хочу сделать, поскольку это ненадежно.

Может кто-нибудь указать мне правильное направление на метод, который обнаружит файлправильно вводите в Java?

Приветствия, Алексей Блю.

Редактировать: Похоже, что конкретного решения для этого нет, как сказал @IronMensan в комментарии ниже.Я нашел эту действительно интересную исследовательскую работу , в которой машинное обучение применяется несколькими способами, чтобы помочь решить проблему, но, похоже, нет полного доказательства ответа.Я думаю, что моя лучшая ставка здесь - попытаться передать файл в программу чтения файлов Excel и перехватить все исключения неправильного формата.

Ответы [ 3 ]

28 голосов
/ 12 февраля 2012

На данный момент самый точный инструмент для определения типа файла 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 будет использовать магические числа, но в случае неуверенности будет смотреть на содержимое файлов, процесс может занять немного времени-дорогой (моему компьютеру потребовалось 3,268 секунды для проверки 15 файлов).

Кроме того, не делайте ту же ошибку, которую я совершил сначала.Если вы получите tika-core JAR, вы также должны получить tika-parsers JAR.Если вы не получите tika-parsers , вы не получите никаких исключений, вы просто не получите тип MIME точно, поэтому ДЕЙСТВИТЕЛЬНО важно включить его.

Альтернативаэто получить tika-app JAR, который содержит tika-core , tika-parsers и все зависимости (их много: poi, poi-ooxml, xmlbeans, commons-compress, только некоторые из них).

3 голосов
/ 16 декабря 2011

Как упомянуто в комментариях, поскольку существует так много возможных типов файлов, которые можно пропустить и пропустить для ВСЕХ возможных файлов, но вы, вероятно, знаете типы файлов, с которыми вы обычно будете иметь дело.Этот превосходный список магических чисел помог мне в последнее время обнаружить определенные офисные форматы, которые вы упомянули (поиск Microsoft Office), и вы увидите, что для типов файлов MS Office указан подтип (которыйнаходится дальше в файл) и позволяет вам определиться, какой тип файла у вас есть.Многие новые форматы, такие как ODT, DOCX, OOXML и т. Д., Используют ZIP-файл для хранения своих данных, поэтому вам может понадобиться сначала определить zip, а затем искать особенности.

0 голосов
/ 04 февраля 2015

Я не совсем уверен, насколько это точно, но у меня это сработало в простых случаях.

    FileNameMap fileNameMap = URLConnection.getFileNameMap();
    String type = fileNameMap.getContentTypeFor(filePath);
...